2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
86 #include "winboard.h"
\r
88 #include "wclipbrd.h"
\r
89 #include "woptions.h"
\r
90 #include "wsockerr.h"
\r
91 #include "defaults.h"
\r
96 #define DATADIR "~~"
\r
98 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
100 int myrandom(void);
\r
101 void mysrandom(unsigned int seed);
\r
103 extern int whiteFlag, blackFlag;
\r
104 Boolean flipClock = FALSE;
\r
105 extern HANDLE chatHandle[];
\r
106 extern enum ICS_TYPE ics_type;
\r
108 int MySearchPath P((char *installDir, char *name, char *fullname));
\r
109 int MyGetFullPathName P((char *name, char *fullname));
\r
110 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
111 VOID NewVariantPopup(HWND hwnd);
\r
112 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
113 /*char*/int promoChar));
\r
114 void DisplayMove P((int moveNumber));
\r
115 void ChatPopUp P((char *s));
\r
117 ChessSquare piece;
\r
118 POINT pos; /* window coordinates of current pos */
\r
119 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
120 POINT from; /* board coordinates of the piece's orig pos */
\r
121 POINT to; /* board coordinates of the piece's new pos */
\r
124 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT start; /* window coordinates of start pos */
\r
128 POINT pos; /* window coordinates of current pos */
\r
129 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
130 POINT from; /* board coordinates of the piece's orig pos */
\r
134 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, EmptySquare };
\r
137 POINT sq[2]; /* board coordinates of from, to squares */
\r
140 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
141 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
142 static HighlightInfo partnerHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
143 static HighlightInfo oldPartnerHighlight = { {{-1, -1}, {-1, -1}} };
\r
145 typedef struct { // [HGM] atomic
\r
146 int fromX, fromY, toX, toY, radius;
\r
149 static ExplodeInfo explodeInfo;
\r
151 /* Window class names */
\r
152 char szAppName[] = "WinBoard";
\r
153 char szConsoleName[] = "WBConsole";
\r
155 /* Title bar text */
\r
156 char szTitle[] = "WinBoard";
\r
157 char szConsoleTitle[] = "I C S Interaction";
\r
160 char *settingsFileName;
\r
161 Boolean saveSettingsOnExit;
\r
162 char installDir[MSG_SIZ];
\r
163 int errorExitStatus;
\r
165 BoardSize boardSize;
\r
166 Boolean chessProgram;
\r
167 //static int boardX, boardY;
\r
168 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
169 int squareSize, lineGap, minorSize, border;
\r
170 static int winW, winH;
\r
171 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
172 static int logoHeight = 0;
\r
173 static char messageText[MESSAGE_TEXT_MAX];
\r
174 static int clockTimerEvent = 0;
\r
175 static int loadGameTimerEvent = 0;
\r
176 static int analysisTimerEvent = 0;
\r
177 static DelayedEventCallback delayedTimerCallback;
\r
178 static int delayedTimerEvent = 0;
\r
179 static int buttonCount = 2;
\r
180 char *icsTextMenuString;
\r
182 char *firstChessProgramNames;
\r
183 char *secondChessProgramNames;
\r
185 #define PALETTESIZE 256
\r
187 HINSTANCE hInst; /* current instance */
\r
188 Boolean alwaysOnTop = FALSE;
\r
190 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
191 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
192 COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };
\r
194 ColorClass currentColorClass;
\r
196 static HWND savedHwnd;
\r
197 HWND hCommPort = NULL; /* currently open comm port */
\r
198 static HWND hwndPause; /* pause button */
\r
199 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
200 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
201 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
202 explodeBrush, /* [HGM] atomic */
\r
203 markerBrush[8], /* [HGM] markers */
\r
204 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
205 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
206 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
207 static HPEN gridPen = NULL;
\r
208 static HPEN highlightPen = NULL;
\r
209 static HPEN premovePen = NULL;
\r
210 static NPLOGPALETTE pLogPal;
\r
211 static BOOL paletteChanged = FALSE;
\r
212 static HICON iconWhite, iconBlack, iconCurrent;
\r
213 static int doingSizing = FALSE;
\r
214 static int lastSizing = 0;
\r
215 static int prevStderrPort;
\r
216 static HBITMAP userLogo;
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
229 #if defined(_winmajor)
\r
230 #define oldDialog (_winmajor < 4)
\r
232 #define oldDialog 0
\r
236 #define INTERNATIONAL
\r
238 #ifdef INTERNATIONAL
\r
239 # define _(s) T_(s)
\r
245 # define Translate(x, y)
\r
246 # define LoadLanguageFile(s)
\r
249 #ifdef INTERNATIONAL
\r
251 Boolean barbaric; // flag indicating if translation is needed
\r
253 // list of item numbers used in each dialog (used to alter language at run time)
\r
255 #define ABOUTBOX -1 /* not sure why these are needed */
\r
256 #define ABOUTBOX2 -1
\r
258 int dialogItems[][42] = {
\r
259 { ABOUTBOX, IDOK, OPT_MESS, 400 },
\r
260 { DLG_TimeControl, IDC_Babble, OPT_TCUseMoves, OPT_TCUseInc, OPT_TCUseFixed,
\r
261 OPT_TCtext1, OPT_TCtext2, OPT_TCitext1, OPT_TCitext2, OPT_TCftext, GPB_Factors, IDC_Factor1, IDC_Factor2, IDOK, IDCANCEL },
\r
262 { DLG_LoadOptions, OPT_Autostep, OPT_AStext1, OPT_Exact, OPT_Subset, OPT_Struct, OPT_Material, OPT_Range, OPT_Difference,
\r
263 OPT_elo1t, OPT_elo2t, OPT_datet, OPT_Stretch, OPT_Stretcht, OPT_Reversed, OPT_SearchMode, OPT_Mirror, OPT_thresholds, IDOK, IDCANCEL },
\r
264 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
265 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
266 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
267 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
268 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
269 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
270 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
271 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
272 { ABOUTBOX2, IDC_ChessBoard },
\r
273 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
274 OPT_GameListClose, IDC_GameListDoFilter },
\r
275 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
276 { DLG_Error, IDOK },
\r
277 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
278 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
279 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
280 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
281 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
282 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
283 { DLG_IndexNumber, IDC_Index },
\r
284 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
285 { DLG_TypeInName, IDOK, IDCANCEL },
\r
286 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
287 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
288 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
289 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
290 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
291 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
292 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
293 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
294 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
295 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
296 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
297 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
298 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
299 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
300 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
301 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
302 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
303 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
304 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
305 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
306 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
307 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
308 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
309 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
310 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
311 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
312 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
313 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
314 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
315 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
316 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
317 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
318 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
319 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
320 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
321 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
322 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
323 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
324 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
325 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
326 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
327 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
328 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
329 { DLG_MoveHistory },
\r
330 { DLG_EvalGraph },
\r
331 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
332 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
333 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
334 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
335 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
336 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
337 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
338 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
339 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
343 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
344 static int lastChecked;
\r
345 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
346 extern int tinyLayout;
\r
347 extern char * menuBarText[][10];
\r
350 LoadLanguageFile(char *name)
\r
351 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
353 int i=0, j=0, n=0, k;
\r
356 if(!name || name[0] == NULLCHAR) return;
\r
357 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
358 appData.language = oldLanguage;
\r
359 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
360 if((f = fopen(buf, "r")) == NULL) return;
\r
361 while((k = fgetc(f)) != EOF) {
\r
362 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
363 languageBuf[i] = k;
\r
365 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
367 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
368 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
369 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
370 english[j] = languageBuf + n + 1; *p = 0;
\r
371 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
372 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
377 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
379 case 'n': k = '\n'; break;
\r
380 case 'r': k = '\r'; break;
\r
381 case 't': k = '\t'; break;
\r
383 languageBuf[--i] = k;
\r
388 barbaric = (j != 0);
\r
389 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
394 { // return the translation of the given string
\r
395 // efficiency can be improved a lot...
\r
397 static char buf[MSG_SIZ];
\r
398 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
399 if(!barbaric) return s;
\r
400 if(!s) return ""; // sanity
\r
401 while(english[i]) {
\r
402 if(!strcmp(s, english[i])) return foreign[i];
\r
403 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
404 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
413 Translate(HWND hDlg, int dialogID)
\r
414 { // translate all text items in the given dialog
\r
416 char buf[MSG_SIZ], *s;
\r
417 if(!barbaric) return;
\r
418 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
419 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
420 GetWindowText( hDlg, buf, MSG_SIZ );
\r
422 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
423 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
424 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
425 if(strlen(buf) == 0) continue;
\r
427 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
432 TranslateOneMenu(int i, HMENU subMenu)
\r
435 static MENUITEMINFO info;
\r
437 info.cbSize = sizeof(MENUITEMINFO);
\r
438 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
439 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
441 info.dwTypeData = buf;
\r
442 info.cch = sizeof(buf);
\r
443 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
445 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
446 else menuText[i][j] = strdup(buf); // remember original on first change
\r
448 if(buf[0] == NULLCHAR) continue;
\r
449 info.dwTypeData = T_(buf);
\r
450 info.cch = strlen(buf)+1;
\r
451 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
457 TranslateMenus(int addLanguage)
\r
460 WIN32_FIND_DATA fileData;
\r
462 #define IDM_English 1970
\r
464 HMENU mainMenu = GetMenu(hwndMain);
\r
465 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
466 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
467 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
468 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
469 TranslateOneMenu(i, subMenu);
\r
471 DrawMenuBar(hwndMain);
\r
474 if(!addLanguage) return;
\r
475 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
476 HMENU mainMenu = GetMenu(hwndMain);
\r
477 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
478 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
479 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
480 i = 0; lastChecked = IDM_English;
\r
482 char *p, *q = fileData.cFileName;
\r
483 int checkFlag = MF_UNCHECKED;
\r
484 languageFile[i] = strdup(q);
\r
485 if(barbaric && !strcmp(oldLanguage, q)) {
\r
486 checkFlag = MF_CHECKED;
\r
487 lastChecked = IDM_English + i + 1;
\r
488 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
490 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
491 p = strstr(fileData.cFileName, ".lng");
\r
493 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
494 } while(FindNextFile(hFind, &fileData));
\r
501 #define IDM_RecentEngines 3000
\r
504 RecentEngineMenu (char *s)
\r
506 if(appData.icsActive) return;
\r
507 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
508 HMENU mainMenu = GetMenu(hwndMain);
\r
509 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
510 int i=IDM_RecentEngines;
\r
511 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
512 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
514 char *p = strchr(s, '\n');
\r
515 if(p == NULL) return; // malformed!
\r
517 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
531 int cliWidth, cliHeight;
\r
534 SizeInfo sizeInfo[] =
\r
536 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
537 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
538 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
539 { "petite", 33, 1, 1, 1, 0, 0 },
\r
540 { "slim", 37, 2, 1, 0, 0, 0 },
\r
541 { "small", 40, 2, 1, 0, 0, 0 },
\r
542 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
543 { "middling", 49, 2, 0, 0, 0, 0 },
\r
544 { "average", 54, 2, 0, 0, 0, 0 },
\r
545 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
546 { "medium", 64, 3, 0, 0, 0, 0 },
\r
547 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
548 { "large", 80, 3, 0, 0, 0, 0 },
\r
549 { "big", 87, 3, 0, 0, 0, 0 },
\r
550 { "huge", 95, 3, 0, 0, 0, 0 },
\r
551 { "giant", 108, 3, 0, 0, 0, 0 },
\r
552 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
553 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
554 { NULL, 0, 0, 0, 0, 0, 0 }
\r
557 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
558 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
560 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
561 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
562 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
563 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
564 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
565 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
566 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
567 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
568 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
569 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
570 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
571 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
572 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
573 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
574 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
575 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
576 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL), MF (GAMELIST_FONT_ALL) },
\r
577 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL), MF(GAMELIST_FONT_ALL) },
\r
580 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
589 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
590 #define N_BUTTONS 5
\r
592 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
594 {"<<", IDM_ToStart, NULL, NULL},
\r
595 {"<", IDM_Backward, NULL, NULL},
\r
596 {"P", IDM_Pause, NULL, NULL},
\r
597 {">", IDM_Forward, NULL, NULL},
\r
598 {">>", IDM_ToEnd, NULL, NULL},
\r
601 int tinyLayout = 0, smallLayout = 0;
\r
602 #define MENU_BAR_ITEMS 9
\r
603 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
604 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
605 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
609 MySound sounds[(int)NSoundClasses];
\r
610 MyTextAttribs textAttribs[(int)NColorClasses];
\r
612 MyColorizeAttribs colorizeAttribs[] = {
\r
613 { (COLORREF)0, 0, N_("Shout Text") },
\r
614 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
615 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
616 { (COLORREF)0, 0, N_("Channel Text") },
\r
617 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
618 { (COLORREF)0, 0, N_("Tell Text") },
\r
619 { (COLORREF)0, 0, N_("Challenge Text") },
\r
620 { (COLORREF)0, 0, N_("Request Text") },
\r
621 { (COLORREF)0, 0, N_("Seek Text") },
\r
622 { (COLORREF)0, 0, N_("Normal Text") },
\r
623 { (COLORREF)0, 0, N_("None") }
\r
628 static char *commentTitle;
\r
629 static char *commentText;
\r
630 static int commentIndex;
\r
631 static Boolean editComment = FALSE;
\r
634 char errorTitle[MSG_SIZ];
\r
635 char errorMessage[2*MSG_SIZ];
\r
636 HWND errorDialog = NULL;
\r
637 BOOLEAN moveErrorMessageUp = FALSE;
\r
638 BOOLEAN consoleEcho = TRUE;
\r
639 CHARFORMAT consoleCF;
\r
640 COLORREF consoleBackgroundColor;
\r
642 char *programVersion;
\r
648 typedef int CPKind;
\r
657 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
660 #define INPUT_SOURCE_BUF_SIZE 4096
\r
662 typedef struct _InputSource {
\r
669 char buf[INPUT_SOURCE_BUF_SIZE];
\r
673 InputCallback func;
\r
674 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
678 InputSource *consoleInputSource;
\r
683 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
684 VOID ConsoleCreate();
\r
686 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
687 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
688 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
689 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
691 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
692 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
693 void ParseIcsTextMenu(char *icsTextMenuString);
\r
694 VOID PopUpNameDialog(char firstchar);
\r
695 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
699 int GameListOptions();
\r
701 int dummy; // [HGM] for obsolete args
\r
703 HWND hwndMain = NULL; /* root window*/
\r
704 HWND hwndConsole = NULL;
\r
705 HWND commentDialog = NULL;
\r
706 HWND moveHistoryDialog = NULL;
\r
707 HWND evalGraphDialog = NULL;
\r
708 HWND engineOutputDialog = NULL;
\r
709 HWND gameListDialog = NULL;
\r
710 HWND editTagsDialog = NULL;
\r
712 int commentUp = FALSE;
\r
714 WindowPlacement wpMain;
\r
715 WindowPlacement wpConsole;
\r
716 WindowPlacement wpComment;
\r
717 WindowPlacement wpMoveHistory;
\r
718 WindowPlacement wpEvalGraph;
\r
719 WindowPlacement wpEngineOutput;
\r
720 WindowPlacement wpGameList;
\r
721 WindowPlacement wpTags;
\r
723 VOID EngineOptionsPopup(); // [HGM] settings
\r
725 VOID GothicPopUp(char *title, VariantClass variant);
\r
727 * Setting "frozen" should disable all user input other than deleting
\r
728 * the window. We do this while engines are initializing themselves.
\r
730 static int frozen = 0;
\r
731 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
737 if (frozen) return;
\r
739 hmenu = GetMenu(hwndMain);
\r
740 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
741 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
743 DrawMenuBar(hwndMain);
\r
746 /* Undo a FreezeUI */
\r
752 if (!frozen) return;
\r
754 hmenu = GetMenu(hwndMain);
\r
755 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
756 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
758 DrawMenuBar(hwndMain);
\r
761 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
763 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
769 #define JAWS_ALT_INTERCEPT
\r
770 #define JAWS_KBUP_NAVIGATION
\r
771 #define JAWS_KBDOWN_NAVIGATION
\r
772 #define JAWS_MENU_ITEMS
\r
773 #define JAWS_SILENCE
\r
774 #define JAWS_REPLAY
\r
776 #define JAWS_COPYRIGHT
\r
777 #define JAWS_DELETE(X) X
\r
778 #define SAYMACHINEMOVE()
\r
782 /*---------------------------------------------------------------------------*\
\r
786 \*---------------------------------------------------------------------------*/
\r
789 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
790 LPSTR lpCmdLine, int nCmdShow)
\r
793 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 // INITCOMMONCONTROLSEX ex;
\r
798 LoadLibrary("RICHED32.DLL");
\r
799 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
801 if (!InitApplication(hInstance)) {
\r
804 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
811 // InitCommonControlsEx(&ex);
\r
812 InitCommonControls();
\r
814 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
815 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
816 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
818 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
820 while (GetMessage(&msg, /* message structure */
\r
821 NULL, /* handle of window receiving the message */
\r
822 0, /* lowest message to examine */
\r
823 0)) /* highest message to examine */
\r
826 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
827 // [HGM] navigate: switch between all windows with tab
\r
828 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
829 int i, currentElement = 0;
\r
831 // first determine what element of the chain we come from (if any)
\r
832 if(appData.icsActive) {
\r
833 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
834 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
836 if(engineOutputDialog && EngineOutputIsUp()) {
\r
837 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
838 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
840 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
841 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
843 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
844 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
845 if(msg.hwnd == e1) currentElement = 2; else
\r
846 if(msg.hwnd == e2) currentElement = 3; else
\r
847 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
848 if(msg.hwnd == mh) currentElement = 4; else
\r
849 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
850 if(msg.hwnd == hText) currentElement = 5; else
\r
851 if(msg.hwnd == hInput) currentElement = 6; else
\r
852 for (i = 0; i < N_BUTTONS; i++) {
\r
853 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
856 // determine where to go to
\r
857 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
859 currentElement = (currentElement + direction) % 7;
\r
860 switch(currentElement) {
\r
862 h = hwndMain; break; // passing this case always makes the loop exit
\r
864 h = buttonDesc[0].hwnd; break; // could be NULL
\r
866 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
869 if(!EngineOutputIsUp()) continue;
\r
872 if(!MoveHistoryIsUp()) continue;
\r
874 // case 6: // input to eval graph does not seem to get here!
\r
875 // if(!EvalGraphIsUp()) continue;
\r
876 // h = evalGraphDialog; break;
\r
878 if(!appData.icsActive) continue;
\r
882 if(!appData.icsActive) continue;
\r
888 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
889 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
892 continue; // this message now has been processed
\r
896 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
897 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
898 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
899 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
900 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
901 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
902 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
903 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
904 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
905 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
906 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
907 for(i=0; i<MAX_CHAT; i++)
\r
908 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
911 if(done) continue; // [HGM] chat: end patch
\r
912 TranslateMessage(&msg); /* Translates virtual key codes */
\r
913 DispatchMessage(&msg); /* Dispatches message to window */
\r
918 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
921 /*---------------------------------------------------------------------------*\
\r
923 * Initialization functions
\r
925 \*---------------------------------------------------------------------------*/
\r
929 { // update user logo if necessary
\r
930 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
932 if(appData.autoLogo) {
\r
933 curName = UserName();
\r
934 if(strcmp(curName, oldUserName)) {
\r
935 GetCurrentDirectory(MSG_SIZ, dir);
\r
936 SetCurrentDirectory(installDir);
\r
937 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
938 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
939 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
940 if(userLogo == NULL)
\r
941 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
942 SetCurrentDirectory(dir); /* return to prev directory */
\r
948 InitApplication(HINSTANCE hInstance)
\r
952 /* Fill in window class structure with parameters that describe the */
\r
955 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
956 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
957 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
958 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
959 wc.hInstance = hInstance; /* Owner of this class */
\r
960 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
961 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
962 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
963 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
964 wc.lpszClassName = szAppName; /* Name to register as */
\r
966 /* Register the window class and return success/failure code. */
\r
967 if (!RegisterClass(&wc)) return FALSE;
\r
969 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
970 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
972 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
973 wc.hInstance = hInstance;
\r
974 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
975 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
976 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
977 wc.lpszMenuName = NULL;
\r
978 wc.lpszClassName = szConsoleName;
\r
980 if (!RegisterClass(&wc)) return FALSE;
\r
985 /* Set by InitInstance, used by EnsureOnScreen */
\r
986 int screenHeight, screenWidth;
\r
987 RECT screenGeometry;
\r
990 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
992 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
993 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
994 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
995 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
996 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
997 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1001 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1003 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1004 GetCurrentDirectory(MSG_SIZ, dir);
\r
1005 SetCurrentDirectory(installDir);
\r
1006 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1007 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1009 if (cps->programLogo == NULL && appData.debugMode) {
\r
1010 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1012 } else if(appData.autoLogo) {
\r
1013 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1014 char *opponent = "";
\r
1015 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1016 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1017 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1018 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1019 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1020 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1023 if(appData.directory[n] && appData.directory[n][0]) {
\r
1024 SetCurrentDirectory(appData.directory[n]);
\r
1025 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1028 SetCurrentDirectory(dir); /* return to prev directory */
\r
1034 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1035 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1037 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1038 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1039 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1040 liteBackTextureMode = appData.liteBackTextureMode;
\r
1042 if (liteBackTexture == NULL && appData.debugMode) {
\r
1043 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1047 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1048 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1049 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1050 darkBackTextureMode = appData.darkBackTextureMode;
\r
1052 if (darkBackTexture == NULL && appData.debugMode) {
\r
1053 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1058 #ifndef SM_CXVIRTUALSCREEN
\r
1059 #define SM_CXVIRTUALSCREEN 78
\r
1061 #ifndef SM_CYVIRTUALSCREEN
\r
1062 #define SM_CYVIRTUALSCREEN 79
\r
1064 #ifndef SM_XVIRTUALSCREEN
\r
1065 #define SM_XVIRTUALSCREEN 76
\r
1067 #ifndef SM_YVIRTUALSCREEN
\r
1068 #define SM_YVIRTUALSCREEN 77
\r
1074 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1075 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1076 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1077 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1078 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1079 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1080 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1081 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1085 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1087 HWND hwnd; /* Main window handle. */
\r
1089 WINDOWPLACEMENT wp;
\r
1092 hInst = hInstance; /* Store instance handle in our global variable */
\r
1093 programName = szAppName;
\r
1095 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1096 *filepart = NULLCHAR;
\r
1097 SetCurrentDirectory(installDir);
\r
1099 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1101 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1103 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1104 /* xboard, and older WinBoards, controlled the move sound with the
\r
1105 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1106 always turn the option on (so that the backend will call us),
\r
1107 then let the user turn the sound off by setting it to silence if
\r
1108 desired. To accommodate old winboard.ini files saved by old
\r
1109 versions of WinBoard, we also turn off the sound if the option
\r
1110 was initially set to false. [HGM] taken out of InitAppData */
\r
1111 if (!appData.ringBellAfterMoves) {
\r
1112 sounds[(int)SoundMove].name = strdup("");
\r
1113 appData.ringBellAfterMoves = TRUE;
\r
1115 if (appData.debugMode) {
\r
1116 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1117 setbuf(debugFP, NULL);
\r
1120 LoadLanguageFile(appData.language);
\r
1124 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1125 // InitEngineUCI( installDir, &second );
\r
1127 /* Create a main window for this application instance. */
\r
1128 hwnd = CreateWindow(szAppName, szTitle,
\r
1129 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1130 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1131 NULL, NULL, hInstance, NULL);
\r
1134 /* If window could not be created, return "failure" */
\r
1139 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1140 LoadLogo(&first, 0, FALSE);
\r
1141 LoadLogo(&second, 1, appData.icsActive);
\r
1145 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1146 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1147 iconCurrent = iconWhite;
\r
1148 InitDrawingColors();
\r
1150 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1151 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1152 /* Compute window size for each board size, and use the largest
\r
1153 size that fits on this screen as the default. */
\r
1154 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1155 if (boardSize == (BoardSize)-1 &&
\r
1156 winH <= screenHeight
\r
1157 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1158 && winW <= screenWidth) {
\r
1159 boardSize = (BoardSize)ibs;
\r
1163 InitDrawingSizes(boardSize, 0);
\r
1164 RecentEngineMenu(appData.recentEngineList);
\r
1166 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1168 /* [AS] Load textures if specified */
\r
1171 mysrandom( (unsigned) time(NULL) );
\r
1173 /* [AS] Restore layout */
\r
1174 if( wpMoveHistory.visible ) {
\r
1175 MoveHistoryPopUp();
\r
1178 if( wpEvalGraph.visible ) {
\r
1182 if( wpEngineOutput.visible ) {
\r
1183 EngineOutputPopUp();
\r
1186 /* Make the window visible; update its client area; and return "success" */
\r
1187 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1188 wp.length = sizeof(WINDOWPLACEMENT);
\r
1190 wp.showCmd = nCmdShow;
\r
1191 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1192 wp.rcNormalPosition.left = wpMain.x;
\r
1193 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1194 wp.rcNormalPosition.top = wpMain.y;
\r
1195 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1196 SetWindowPlacement(hwndMain, &wp);
\r
1198 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1200 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1201 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1203 if (hwndConsole) {
\r
1205 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1206 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1208 ShowWindow(hwndConsole, nCmdShow);
\r
1209 SetActiveWindow(hwndConsole);
\r
1211 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1212 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1221 HMENU hmenu = GetMenu(hwndMain);
\r
1223 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1224 MF_BYCOMMAND|((appData.icsActive &&
\r
1225 *appData.icsCommPort != NULLCHAR) ?
\r
1226 MF_ENABLED : MF_GRAYED));
\r
1227 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1228 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1229 MF_CHECKED : MF_UNCHECKED));
\r
1232 //---------------------------------------------------------------------------------------------------------
\r
1234 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1235 #define XBOARD FALSE
\r
1237 #define OPTCHAR "/"
\r
1238 #define SEPCHAR "="
\r
1239 #define TOPLEVEL 0
\r
1243 // front-end part of option handling
\r
1246 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1248 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1249 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1252 lf->lfEscapement = 0;
\r
1253 lf->lfOrientation = 0;
\r
1254 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1255 lf->lfItalic = mfp->italic;
\r
1256 lf->lfUnderline = mfp->underline;
\r
1257 lf->lfStrikeOut = mfp->strikeout;
\r
1258 lf->lfCharSet = mfp->charset;
\r
1259 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1260 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1261 lf->lfQuality = DEFAULT_QUALITY;
\r
1262 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1263 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1267 CreateFontInMF(MyFont *mf)
\r
1269 LFfromMFP(&mf->lf, &mf->mfp);
\r
1270 if (mf->hf) DeleteObject(mf->hf);
\r
1271 mf->hf = CreateFontIndirect(&mf->lf);
\r
1274 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1276 colorVariable[] = {
\r
1277 &whitePieceColor,
\r
1278 &blackPieceColor,
\r
1279 &lightSquareColor,
\r
1280 &darkSquareColor,
\r
1281 &highlightSquareColor,
\r
1282 &premoveHighlightColor,
\r
1284 &consoleBackgroundColor,
\r
1285 &appData.fontForeColorWhite,
\r
1286 &appData.fontBackColorWhite,
\r
1287 &appData.fontForeColorBlack,
\r
1288 &appData.fontBackColorBlack,
\r
1289 &appData.evalHistColorWhite,
\r
1290 &appData.evalHistColorBlack,
\r
1291 &appData.highlightArrowColor,
\r
1294 /* Command line font name parser. NULL name means do nothing.
\r
1295 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1296 For backward compatibility, syntax without the colon is also
\r
1297 accepted, but font names with digits in them won't work in that case.
\r
1300 ParseFontName(char *name, MyFontParams *mfp)
\r
1303 if (name == NULL) return;
\r
1305 q = strchr(p, ':');
\r
1307 if (q - p >= sizeof(mfp->faceName))
\r
1308 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1309 memcpy(mfp->faceName, p, q - p);
\r
1310 mfp->faceName[q - p] = NULLCHAR;
\r
1313 q = mfp->faceName;
\r
1315 while (*p && !isdigit(*p)) {
\r
1317 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1318 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1320 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1323 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1324 mfp->pointSize = (float) atof(p);
\r
1325 mfp->bold = (strchr(p, 'b') != NULL);
\r
1326 mfp->italic = (strchr(p, 'i') != NULL);
\r
1327 mfp->underline = (strchr(p, 'u') != NULL);
\r
1328 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1329 mfp->charset = DEFAULT_CHARSET;
\r
1330 q = strchr(p, 'c');
\r
1332 mfp->charset = (BYTE) atoi(q+1);
\r
1336 ParseFont(char *name, int number)
\r
1337 { // wrapper to shield back-end from 'font'
\r
1338 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1343 { // in WB we have a 2D array of fonts; this initializes their description
\r
1345 /* Point font array elements to structures and
\r
1346 parse default font names */
\r
1347 for (i=0; i<NUM_FONTS; i++) {
\r
1348 for (j=0; j<NUM_SIZES; j++) {
\r
1349 font[j][i] = &fontRec[j][i];
\r
1350 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1357 { // here we create the actual fonts from the selected descriptions
\r
1359 for (i=0; i<NUM_FONTS; i++) {
\r
1360 for (j=0; j<NUM_SIZES; j++) {
\r
1361 CreateFontInMF(font[j][i]);
\r
1365 /* Color name parser.
\r
1366 X version accepts X color names, but this one
\r
1367 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1369 ParseColorName(char *name)
\r
1371 int red, green, blue, count;
\r
1372 char buf[MSG_SIZ];
\r
1374 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1376 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1377 &red, &green, &blue);
\r
1380 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1381 DisplayError(buf, 0);
\r
1382 return RGB(0, 0, 0);
\r
1384 return PALETTERGB(red, green, blue);
\r
1388 ParseColor(int n, char *name)
\r
1389 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1390 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1394 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1396 char *e = argValue;
\r
1400 if (*e == 'b') eff |= CFE_BOLD;
\r
1401 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1402 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1403 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1404 else if (*e == '#' || isdigit(*e)) break;
\r
1408 *color = ParseColorName(e);
\r
1412 ParseTextAttribs(ColorClass cc, char *s)
\r
1413 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1414 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1415 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1419 ParseBoardSize(void *addr, char *name)
\r
1420 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1421 BoardSize bs = SizeTiny;
\r
1422 while (sizeInfo[bs].name != NULL) {
\r
1423 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1424 *(BoardSize *)addr = bs;
\r
1429 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1434 { // [HGM] import name from appData first
\r
1437 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1438 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1439 textAttribs[cc].sound.data = NULL;
\r
1440 MyLoadSound(&textAttribs[cc].sound);
\r
1442 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1443 textAttribs[cc].sound.name = strdup("");
\r
1444 textAttribs[cc].sound.data = NULL;
\r
1446 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1447 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1448 sounds[sc].data = NULL;
\r
1449 MyLoadSound(&sounds[sc]);
\r
1454 SetCommPortDefaults()
\r
1456 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1457 dcb.DCBlength = sizeof(DCB);
\r
1458 dcb.BaudRate = 9600;
\r
1459 dcb.fBinary = TRUE;
\r
1460 dcb.fParity = FALSE;
\r
1461 dcb.fOutxCtsFlow = FALSE;
\r
1462 dcb.fOutxDsrFlow = FALSE;
\r
1463 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1464 dcb.fDsrSensitivity = FALSE;
\r
1465 dcb.fTXContinueOnXoff = TRUE;
\r
1466 dcb.fOutX = FALSE;
\r
1468 dcb.fNull = FALSE;
\r
1469 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1470 dcb.fAbortOnError = FALSE;
\r
1472 dcb.Parity = SPACEPARITY;
\r
1473 dcb.StopBits = ONESTOPBIT;
\r
1476 // [HGM] args: these three cases taken out to stay in front-end
\r
1478 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1479 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1480 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1481 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1483 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1484 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1485 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1486 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1487 ad->argName, mfp->faceName, mfp->pointSize,
\r
1488 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1489 mfp->bold ? "b" : "",
\r
1490 mfp->italic ? "i" : "",
\r
1491 mfp->underline ? "u" : "",
\r
1492 mfp->strikeout ? "s" : "",
\r
1493 (int)mfp->charset);
\r
1499 { // [HGM] copy the names from the internal WB variables to appData
\r
1502 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1503 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1504 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1505 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1509 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1510 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1511 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1512 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1513 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1514 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1515 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1516 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1517 (ta->effects) ? " " : "",
\r
1518 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1522 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1523 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1524 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1525 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1526 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1530 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1531 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1532 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1536 ParseCommPortSettings(char *s)
\r
1537 { // wrapper to keep dcb from back-end
\r
1538 ParseCommSettings(s, &dcb);
\r
1543 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1544 GetActualPlacement(hwndMain, &wpMain);
\r
1545 GetActualPlacement(hwndConsole, &wpConsole);
\r
1546 GetActualPlacement(commentDialog, &wpComment);
\r
1547 GetActualPlacement(editTagsDialog, &wpTags);
\r
1548 GetActualPlacement(gameListDialog, &wpGameList);
\r
1549 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1550 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1551 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1555 PrintCommPortSettings(FILE *f, char *name)
\r
1556 { // wrapper to shield back-end from DCB
\r
1557 PrintCommSettings(f, name, &dcb);
\r
1561 MySearchPath(char *installDir, char *name, char *fullname)
\r
1563 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1564 if(name[0]== '%') {
\r
1565 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1566 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1567 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1568 *strchr(buf, '%') = 0;
\r
1569 strcat(fullname, getenv(buf));
\r
1570 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1572 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1573 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1574 return (int) strlen(fullname);
\r
1576 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1580 MyGetFullPathName(char *name, char *fullname)
\r
1583 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1588 { // [HGM] args: allows testing if main window is realized from back-end
\r
1589 return hwndMain != NULL;
\r
1593 PopUpStartupDialog()
\r
1597 LoadLanguageFile(appData.language);
\r
1598 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1599 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1600 FreeProcInstance(lpProc);
\r
1603 /*---------------------------------------------------------------------------*\
\r
1605 * GDI board drawing routines
\r
1607 \*---------------------------------------------------------------------------*/
\r
1609 /* [AS] Draw square using background texture */
\r
1610 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1615 return; /* Should never happen! */
\r
1618 SetGraphicsMode( dst, GM_ADVANCED );
\r
1625 /* X reflection */
\r
1630 x.eDx = (FLOAT) dw + dx - 1;
\r
1633 SetWorldTransform( dst, &x );
\r
1636 /* Y reflection */
\r
1642 x.eDy = (FLOAT) dh + dy - 1;
\r
1644 SetWorldTransform( dst, &x );
\r
1652 x.eDx = (FLOAT) dx;
\r
1653 x.eDy = (FLOAT) dy;
\r
1656 SetWorldTransform( dst, &x );
\r
1660 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1668 SetWorldTransform( dst, &x );
\r
1670 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1673 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1675 PM_WP = (int) WhitePawn,
\r
1676 PM_WN = (int) WhiteKnight,
\r
1677 PM_WB = (int) WhiteBishop,
\r
1678 PM_WR = (int) WhiteRook,
\r
1679 PM_WQ = (int) WhiteQueen,
\r
1680 PM_WF = (int) WhiteFerz,
\r
1681 PM_WW = (int) WhiteWazir,
\r
1682 PM_WE = (int) WhiteAlfil,
\r
1683 PM_WM = (int) WhiteMan,
\r
1684 PM_WO = (int) WhiteCannon,
\r
1685 PM_WU = (int) WhiteUnicorn,
\r
1686 PM_WH = (int) WhiteNightrider,
\r
1687 PM_WA = (int) WhiteAngel,
\r
1688 PM_WC = (int) WhiteMarshall,
\r
1689 PM_WAB = (int) WhiteCardinal,
\r
1690 PM_WD = (int) WhiteDragon,
\r
1691 PM_WL = (int) WhiteLance,
\r
1692 PM_WS = (int) WhiteCobra,
\r
1693 PM_WV = (int) WhiteFalcon,
\r
1694 PM_WSG = (int) WhiteSilver,
\r
1695 PM_WG = (int) WhiteGrasshopper,
\r
1696 PM_WK = (int) WhiteKing,
\r
1697 PM_BP = (int) BlackPawn,
\r
1698 PM_BN = (int) BlackKnight,
\r
1699 PM_BB = (int) BlackBishop,
\r
1700 PM_BR = (int) BlackRook,
\r
1701 PM_BQ = (int) BlackQueen,
\r
1702 PM_BF = (int) BlackFerz,
\r
1703 PM_BW = (int) BlackWazir,
\r
1704 PM_BE = (int) BlackAlfil,
\r
1705 PM_BM = (int) BlackMan,
\r
1706 PM_BO = (int) BlackCannon,
\r
1707 PM_BU = (int) BlackUnicorn,
\r
1708 PM_BH = (int) BlackNightrider,
\r
1709 PM_BA = (int) BlackAngel,
\r
1710 PM_BC = (int) BlackMarshall,
\r
1711 PM_BG = (int) BlackGrasshopper,
\r
1712 PM_BAB = (int) BlackCardinal,
\r
1713 PM_BD = (int) BlackDragon,
\r
1714 PM_BL = (int) BlackLance,
\r
1715 PM_BS = (int) BlackCobra,
\r
1716 PM_BV = (int) BlackFalcon,
\r
1717 PM_BSG = (int) BlackSilver,
\r
1718 PM_BK = (int) BlackKing
\r
1721 static HFONT hPieceFont = NULL;
\r
1722 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1723 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1724 static int fontBitmapSquareSize = 0;
\r
1725 static char pieceToFontChar[(int) EmptySquare] =
\r
1726 { 'p', 'n', 'b', 'r', 'q',
\r
1727 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1728 'k', 'o', 'm', 'v', 't', 'w',
\r
1729 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1732 extern BOOL SetCharTable( char *table, const char * map );
\r
1733 /* [HGM] moved to backend.c */
\r
1735 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1738 BYTE r1 = GetRValue( color );
\r
1739 BYTE g1 = GetGValue( color );
\r
1740 BYTE b1 = GetBValue( color );
\r
1746 /* Create a uniform background first */
\r
1747 hbrush = CreateSolidBrush( color );
\r
1748 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1749 FillRect( hdc, &rc, hbrush );
\r
1750 DeleteObject( hbrush );
\r
1753 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1754 int steps = squareSize / 2;
\r
1757 for( i=0; i<steps; i++ ) {
\r
1758 BYTE r = r1 - (r1-r2) * i / steps;
\r
1759 BYTE g = g1 - (g1-g2) * i / steps;
\r
1760 BYTE b = b1 - (b1-b2) * i / steps;
\r
1762 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1763 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1764 FillRect( hdc, &rc, hbrush );
\r
1765 DeleteObject(hbrush);
\r
1768 else if( mode == 2 ) {
\r
1769 /* Diagonal gradient, good more or less for every piece */
\r
1770 POINT triangle[3];
\r
1771 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1772 HBRUSH hbrush_old;
\r
1773 int steps = squareSize;
\r
1776 triangle[0].x = squareSize - steps;
\r
1777 triangle[0].y = squareSize;
\r
1778 triangle[1].x = squareSize;
\r
1779 triangle[1].y = squareSize;
\r
1780 triangle[2].x = squareSize;
\r
1781 triangle[2].y = squareSize - steps;
\r
1783 for( i=0; i<steps; i++ ) {
\r
1784 BYTE r = r1 - (r1-r2) * i / steps;
\r
1785 BYTE g = g1 - (g1-g2) * i / steps;
\r
1786 BYTE b = b1 - (b1-b2) * i / steps;
\r
1788 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1789 hbrush_old = SelectObject( hdc, hbrush );
\r
1790 Polygon( hdc, triangle, 3 );
\r
1791 SelectObject( hdc, hbrush_old );
\r
1792 DeleteObject(hbrush);
\r
1797 SelectObject( hdc, hpen );
\r
1802 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1803 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1804 piece: follow the steps as explained below.
\r
1806 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1810 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1814 int backColor = whitePieceColor;
\r
1815 int foreColor = blackPieceColor;
\r
1817 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1818 backColor = appData.fontBackColorWhite;
\r
1819 foreColor = appData.fontForeColorWhite;
\r
1821 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1822 backColor = appData.fontBackColorBlack;
\r
1823 foreColor = appData.fontForeColorBlack;
\r
1827 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1829 hbm_old = SelectObject( hdc, hbm );
\r
1833 rc.right = squareSize;
\r
1834 rc.bottom = squareSize;
\r
1836 /* Step 1: background is now black */
\r
1837 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1839 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1841 pt.x = (squareSize - sz.cx) / 2;
\r
1842 pt.y = (squareSize - sz.cy) / 2;
\r
1844 SetBkMode( hdc, TRANSPARENT );
\r
1845 SetTextColor( hdc, chroma );
\r
1846 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1847 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1849 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1850 /* Step 3: the area outside the piece is filled with white */
\r
1851 // FloodFill( hdc, 0, 0, chroma );
\r
1852 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1853 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1854 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1855 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1856 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1858 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1859 but if the start point is not inside the piece we're lost!
\r
1860 There should be a better way to do this... if we could create a region or path
\r
1861 from the fill operation we would be fine for example.
\r
1863 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1864 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1866 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1867 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1868 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1870 SelectObject( dc2, bm2 );
\r
1871 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1872 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1873 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1874 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1875 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1878 DeleteObject( bm2 );
\r
1881 SetTextColor( hdc, 0 );
\r
1883 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1884 draw the piece again in black for safety.
\r
1886 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1888 SelectObject( hdc, hbm_old );
\r
1890 if( hPieceMask[index] != NULL ) {
\r
1891 DeleteObject( hPieceMask[index] );
\r
1894 hPieceMask[index] = hbm;
\r
1897 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1899 SelectObject( hdc, hbm );
\r
1902 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1903 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1904 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1906 SelectObject( dc1, hPieceMask[index] );
\r
1907 SelectObject( dc2, bm2 );
\r
1908 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1909 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1912 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1913 the piece background and deletes (makes transparent) the rest.
\r
1914 Thanks to that mask, we are free to paint the background with the greates
\r
1915 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1916 We use this, to make gradients and give the pieces a "roundish" look.
\r
1918 SetPieceBackground( hdc, backColor, 2 );
\r
1919 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1923 DeleteObject( bm2 );
\r
1926 SetTextColor( hdc, foreColor );
\r
1927 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1929 SelectObject( hdc, hbm_old );
\r
1931 if( hPieceFace[index] != NULL ) {
\r
1932 DeleteObject( hPieceFace[index] );
\r
1935 hPieceFace[index] = hbm;
\r
1938 static int TranslatePieceToFontPiece( int piece )
\r
1968 case BlackMarshall:
\r
1972 case BlackNightrider:
\r
1978 case BlackUnicorn:
\r
1982 case BlackGrasshopper:
\r
1994 case BlackCardinal:
\r
2001 case WhiteMarshall:
\r
2005 case WhiteNightrider:
\r
2011 case WhiteUnicorn:
\r
2015 case WhiteGrasshopper:
\r
2027 case WhiteCardinal:
\r
2036 void CreatePiecesFromFont()
\r
2039 HDC hdc_window = NULL;
\r
2045 if( fontBitmapSquareSize < 0 ) {
\r
2046 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2050 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2051 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2052 fontBitmapSquareSize = -1;
\r
2056 if( fontBitmapSquareSize != squareSize ) {
\r
2057 hdc_window = GetDC( hwndMain );
\r
2058 hdc = CreateCompatibleDC( hdc_window );
\r
2060 if( hPieceFont != NULL ) {
\r
2061 DeleteObject( hPieceFont );
\r
2064 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2065 hPieceMask[i] = NULL;
\r
2066 hPieceFace[i] = NULL;
\r
2072 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2073 fontHeight = appData.fontPieceSize;
\r
2076 fontHeight = (fontHeight * squareSize) / 100;
\r
2078 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2080 lf.lfEscapement = 0;
\r
2081 lf.lfOrientation = 0;
\r
2082 lf.lfWeight = FW_NORMAL;
\r
2084 lf.lfUnderline = 0;
\r
2085 lf.lfStrikeOut = 0;
\r
2086 lf.lfCharSet = DEFAULT_CHARSET;
\r
2087 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2088 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2089 lf.lfQuality = PROOF_QUALITY;
\r
2090 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2091 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2092 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2094 hPieceFont = CreateFontIndirect( &lf );
\r
2096 if( hPieceFont == NULL ) {
\r
2097 fontBitmapSquareSize = -2;
\r
2100 /* Setup font-to-piece character table */
\r
2101 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2102 /* No (or wrong) global settings, try to detect the font */
\r
2103 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2105 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2107 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2108 /* DiagramTT* family */
\r
2109 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2111 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2112 /* Fairy symbols */
\r
2113 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2115 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2116 /* Good Companion (Some characters get warped as literal :-( */
\r
2117 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2118 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2119 SetCharTable(pieceToFontChar, s);
\r
2122 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2123 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2127 /* Create bitmaps */
\r
2128 hfont_old = SelectObject( hdc, hPieceFont );
\r
2129 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2130 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2131 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2133 SelectObject( hdc, hfont_old );
\r
2135 fontBitmapSquareSize = squareSize;
\r
2139 if( hdc != NULL ) {
\r
2143 if( hdc_window != NULL ) {
\r
2144 ReleaseDC( hwndMain, hdc_window );
\r
2149 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2151 char name[128], buf[MSG_SIZ];
\r
2153 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2154 if(appData.pieceDirectory[0]) {
\r
2156 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2157 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2158 if(res) return res;
\r
2160 if (gameInfo.event &&
\r
2161 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2162 strcmp(name, "k80s") == 0) {
\r
2163 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2165 return LoadBitmap(hinst, name);
\r
2169 /* Insert a color into the program's logical palette
\r
2170 structure. This code assumes the given color is
\r
2171 the result of the RGB or PALETTERGB macro, and it
\r
2172 knows how those macros work (which is documented).
\r
2175 InsertInPalette(COLORREF color)
\r
2177 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2179 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2180 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2181 pLogPal->palNumEntries--;
\r
2185 pe->peFlags = (char) 0;
\r
2186 pe->peRed = (char) (0xFF & color);
\r
2187 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2188 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2194 InitDrawingColors()
\r
2197 if (pLogPal == NULL) {
\r
2198 /* Allocate enough memory for a logical palette with
\r
2199 * PALETTESIZE entries and set the size and version fields
\r
2200 * of the logical palette structure.
\r
2202 pLogPal = (NPLOGPALETTE)
\r
2203 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2204 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2205 pLogPal->palVersion = 0x300;
\r
2207 pLogPal->palNumEntries = 0;
\r
2209 InsertInPalette(lightSquareColor);
\r
2210 InsertInPalette(darkSquareColor);
\r
2211 InsertInPalette(whitePieceColor);
\r
2212 InsertInPalette(blackPieceColor);
\r
2213 InsertInPalette(highlightSquareColor);
\r
2214 InsertInPalette(premoveHighlightColor);
\r
2216 /* create a logical color palette according the information
\r
2217 * in the LOGPALETTE structure.
\r
2219 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2221 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2222 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2223 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2224 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2225 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2226 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2227 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2228 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2230 /* [AS] Force rendering of the font-based pieces */
\r
2231 if( fontBitmapSquareSize > 0 ) {
\r
2232 fontBitmapSquareSize = 0;
\r
2238 BoardWidth(int boardSize, int n)
\r
2239 { /* [HGM] argument n added to allow different width and height */
\r
2240 int lineGap = sizeInfo[boardSize].lineGap;
\r
2242 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2243 lineGap = appData.overrideLineGap;
\r
2246 return (n + 1) * lineGap +
\r
2247 n * sizeInfo[boardSize].squareSize;
\r
2250 /* Respond to board resize by dragging edge */
\r
2252 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2254 BoardSize newSize = NUM_SIZES - 1;
\r
2255 static int recurse = 0;
\r
2256 if (IsIconic(hwndMain)) return;
\r
2257 if (recurse > 0) return;
\r
2259 while (newSize > 0) {
\r
2260 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2261 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2262 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2265 boardSize = newSize;
\r
2266 InitDrawingSizes(boardSize, flags);
\r
2271 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2274 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2276 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2277 ChessSquare piece;
\r
2278 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2280 SIZE clockSize, messageSize;
\r
2282 char buf[MSG_SIZ];
\r
2284 HMENU hmenu = GetMenu(hwndMain);
\r
2285 RECT crect, wrect, oldRect;
\r
2287 LOGBRUSH logbrush;
\r
2288 VariantClass v = gameInfo.variant;
\r
2290 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2291 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2293 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2294 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2295 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2296 oldBoardSize = boardSize;
\r
2298 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2299 { // correct board size to one where built-in pieces exist
\r
2300 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2301 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2302 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2303 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2304 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2305 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2306 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2307 boardSize = SizeMiddling;
\r
2310 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2312 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2313 oldRect.top = wpMain.y;
\r
2314 oldRect.right = wpMain.x + wpMain.width;
\r
2315 oldRect.bottom = wpMain.y + wpMain.height;
\r
2317 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2318 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2319 squareSize = sizeInfo[boardSize].squareSize;
\r
2320 lineGap = sizeInfo[boardSize].lineGap;
\r
2321 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2322 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2324 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2325 lineGap = appData.overrideLineGap;
\r
2328 if (tinyLayout != oldTinyLayout) {
\r
2329 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2331 style &= ~WS_SYSMENU;
\r
2332 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2333 "&Minimize\tCtrl+F4");
\r
2335 style |= WS_SYSMENU;
\r
2336 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2338 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2340 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2341 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2342 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2344 DrawMenuBar(hwndMain);
\r
2347 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2348 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2350 /* Get text area sizes */
\r
2351 hdc = GetDC(hwndMain);
\r
2352 if (appData.clockMode) {
\r
2353 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2355 snprintf(buf, MSG_SIZ, _("White"));
\r
2357 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2358 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2359 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2360 str = _("We only care about the height here");
\r
2361 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2362 SelectObject(hdc, oldFont);
\r
2363 ReleaseDC(hwndMain, hdc);
\r
2365 /* Compute where everything goes */
\r
2366 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
2367 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2368 logoHeight = 2*clockSize.cy;
\r
2369 leftLogoRect.left = OUTER_MARGIN;
\r
2370 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2371 leftLogoRect.top = OUTER_MARGIN;
\r
2372 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2374 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2375 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2376 rightLogoRect.top = OUTER_MARGIN;
\r
2377 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2380 whiteRect.left = leftLogoRect.right;
\r
2381 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2382 whiteRect.top = OUTER_MARGIN;
\r
2383 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2385 blackRect.right = rightLogoRect.left;
\r
2386 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2387 blackRect.top = whiteRect.top;
\r
2388 blackRect.bottom = whiteRect.bottom;
\r
2390 whiteRect.left = OUTER_MARGIN;
\r
2391 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2392 whiteRect.top = OUTER_MARGIN;
\r
2393 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2395 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2396 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2397 blackRect.top = whiteRect.top;
\r
2398 blackRect.bottom = whiteRect.bottom;
\r
2400 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2403 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2404 if (appData.showButtonBar) {
\r
2405 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2406 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2408 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2410 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2411 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2413 boardRect.left = OUTER_MARGIN;
\r
2414 boardRect.right = boardRect.left + boardWidth;
\r
2415 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2416 boardRect.bottom = boardRect.top + boardHeight;
\r
2418 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2419 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2420 oldTinyLayout = tinyLayout;
\r
2421 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2422 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2423 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2424 winW *= 1 + twoBoards;
\r
2425 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2426 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2427 wpMain.height = winH; // without disturbing window attachments
\r
2428 GetWindowRect(hwndMain, &wrect);
\r
2429 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2430 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2432 // [HGM] placement: let attached windows follow size change.
\r
2433 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2434 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2435 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2436 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2437 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2439 /* compensate if menu bar wrapped */
\r
2440 GetClientRect(hwndMain, &crect);
\r
2441 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2442 wpMain.height += offby;
\r
2444 case WMSZ_TOPLEFT:
\r
2445 SetWindowPos(hwndMain, NULL,
\r
2446 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2447 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2450 case WMSZ_TOPRIGHT:
\r
2452 SetWindowPos(hwndMain, NULL,
\r
2453 wrect.left, wrect.bottom - wpMain.height,
\r
2454 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2457 case WMSZ_BOTTOMLEFT:
\r
2459 SetWindowPos(hwndMain, NULL,
\r
2460 wrect.right - wpMain.width, wrect.top,
\r
2461 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2464 case WMSZ_BOTTOMRIGHT:
\r
2468 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2469 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2474 for (i = 0; i < N_BUTTONS; i++) {
\r
2475 if (buttonDesc[i].hwnd != NULL) {
\r
2476 DestroyWindow(buttonDesc[i].hwnd);
\r
2477 buttonDesc[i].hwnd = NULL;
\r
2479 if (appData.showButtonBar) {
\r
2480 buttonDesc[i].hwnd =
\r
2481 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2482 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2483 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2484 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2485 (HMENU) buttonDesc[i].id,
\r
2486 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2488 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2489 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2490 MAKELPARAM(FALSE, 0));
\r
2492 if (buttonDesc[i].id == IDM_Pause)
\r
2493 hwndPause = buttonDesc[i].hwnd;
\r
2494 buttonDesc[i].wndproc = (WNDPROC)
\r
2495 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2498 if (gridPen != NULL) DeleteObject(gridPen);
\r
2499 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2500 if (premovePen != NULL) DeleteObject(premovePen);
\r
2501 if (lineGap != 0) {
\r
2502 logbrush.lbStyle = BS_SOLID;
\r
2503 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2505 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2506 lineGap, &logbrush, 0, NULL);
\r
2507 logbrush.lbColor = highlightSquareColor;
\r
2509 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2510 lineGap, &logbrush, 0, NULL);
\r
2512 logbrush.lbColor = premoveHighlightColor;
\r
2514 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2515 lineGap, &logbrush, 0, NULL);
\r
2517 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2518 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2519 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2520 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2521 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2522 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2523 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2524 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2526 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2527 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2528 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2529 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2530 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2531 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2532 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2533 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2537 /* [HGM] Licensing requirement */
\r
2539 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2542 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2544 GothicPopUp( "", VariantNormal);
\r
2547 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2549 /* Load piece bitmaps for this board size */
\r
2550 for (i=0; i<=2; i++) {
\r
2551 for (piece = WhitePawn;
\r
2552 (int) piece < (int) BlackPawn;
\r
2553 piece = (ChessSquare) ((int) piece + 1)) {
\r
2554 if (pieceBitmap[i][piece] != NULL)
\r
2555 DeleteObject(pieceBitmap[i][piece]);
\r
2559 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2560 // Orthodox Chess pieces
\r
2561 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2562 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2563 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2564 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2565 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2566 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2567 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2568 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2569 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2570 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2571 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2572 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2573 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2574 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2575 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2576 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2577 // in Shogi, Hijack the unused Queen for Lance
\r
2578 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2579 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2580 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2582 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2583 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2584 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2587 if(squareSize <= 72 && squareSize >= 33) {
\r
2588 /* A & C are available in most sizes now */
\r
2589 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2590 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2591 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2592 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2593 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2594 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2595 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2596 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2597 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2598 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2599 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2600 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2601 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2602 } else { // Smirf-like
\r
2603 if(gameInfo.variant == VariantSChess) {
\r
2604 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2605 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2606 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2608 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2609 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2610 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2613 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2614 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2617 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2618 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2621 } else { // WinBoard standard
\r
2622 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2623 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2624 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2629 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2630 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2631 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2632 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2633 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2636 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2637 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2638 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2639 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2640 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2641 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2642 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2645 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2646 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2647 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2648 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2649 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2650 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2651 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2652 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2653 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2654 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2657 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2658 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2659 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2660 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2664 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
2665 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2668 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2678 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2679 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2680 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2681 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2692 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2693 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2694 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2695 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2696 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2697 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2698 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2699 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2700 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2701 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2702 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2703 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2704 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2705 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2706 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2710 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2711 /* special Shogi support in this size */
\r
2712 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2713 for (piece = WhitePawn;
\r
2714 (int) piece < (int) BlackPawn;
\r
2715 piece = (ChessSquare) ((int) piece + 1)) {
\r
2716 if (pieceBitmap[i][piece] != NULL)
\r
2717 DeleteObject(pieceBitmap[i][piece]);
\r
2720 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2721 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2722 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2723 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2724 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2725 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2726 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2727 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2728 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2729 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2730 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2731 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2732 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2733 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2734 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2735 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2736 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2737 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2738 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2739 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2740 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2741 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2742 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2743 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2744 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2745 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2746 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2747 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2748 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2749 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2750 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2751 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2752 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2753 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2754 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2755 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2756 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2757 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2758 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2759 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2760 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2761 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2767 PieceBitmap(ChessSquare p, int kind)
\r
2769 if ((int) p >= (int) BlackPawn)
\r
2770 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2772 return pieceBitmap[kind][(int) p];
\r
2775 /***************************************************************/
\r
2777 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2778 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2780 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2781 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2785 SquareToPos(int row, int column, int * x, int * y)
\r
2788 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2789 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2791 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2792 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2797 DrawCoordsOnDC(HDC hdc)
\r
2799 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2800 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2801 char str[2] = { NULLCHAR, NULLCHAR };
\r
2802 int oldMode, oldAlign, x, y, start, i;
\r
2806 if (!appData.showCoords)
\r
2809 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2811 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2812 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2813 oldAlign = GetTextAlign(hdc);
\r
2814 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2816 y = boardRect.top + lineGap;
\r
2817 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2820 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2821 x += border - lineGap - 4; y += squareSize - 6;
\r
2823 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2824 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2825 str[0] = files[start + i];
\r
2826 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2827 y += squareSize + lineGap;
\r
2830 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2833 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2834 x += -border + 4; y += border - squareSize + 6;
\r
2836 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2837 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2838 str[0] = ranks[start + i];
\r
2839 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2840 x += squareSize + lineGap;
\r
2843 SelectObject(hdc, oldBrush);
\r
2844 SetBkMode(hdc, oldMode);
\r
2845 SetTextAlign(hdc, oldAlign);
\r
2846 SelectObject(hdc, oldFont);
\r
2850 DrawGridOnDC(HDC hdc)
\r
2854 if (lineGap != 0) {
\r
2855 oldPen = SelectObject(hdc, gridPen);
\r
2856 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2857 SelectObject(hdc, oldPen);
\r
2861 #define HIGHLIGHT_PEN 0
\r
2862 #define PREMOVE_PEN 1
\r
2865 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2868 HPEN oldPen, hPen;
\r
2869 if (lineGap == 0) return;
\r
2871 x1 = boardRect.left +
\r
2872 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2873 y1 = boardRect.top +
\r
2874 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2876 x1 = boardRect.left +
\r
2877 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2878 y1 = boardRect.top +
\r
2879 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2881 hPen = pen ? premovePen : highlightPen;
\r
2882 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2883 MoveToEx(hdc, x1, y1, NULL);
\r
2884 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2885 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2886 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2887 LineTo(hdc, x1, y1);
\r
2888 SelectObject(hdc, oldPen);
\r
2892 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2895 for (i=0; i<2; i++) {
\r
2896 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2897 DrawHighlightOnDC(hdc, TRUE,
\r
2898 h->sq[i].x, h->sq[i].y,
\r
2903 /* Note: sqcolor is used only in monoMode */
\r
2904 /* Note that this code is largely duplicated in woptions.c,
\r
2905 function DrawSampleSquare, so that needs to be updated too */
\r
2907 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2909 HBITMAP oldBitmap;
\r
2913 if (appData.blindfold) return;
\r
2915 /* [AS] Use font-based pieces if needed */
\r
2916 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2917 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2918 CreatePiecesFromFont();
\r
2920 if( fontBitmapSquareSize == squareSize ) {
\r
2921 int index = TranslatePieceToFontPiece(piece);
\r
2923 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2925 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2926 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2930 squareSize, squareSize,
\r
2935 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2937 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2938 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2942 squareSize, squareSize,
\r
2951 if (appData.monoMode) {
\r
2952 SelectObject(tmphdc, PieceBitmap(piece,
\r
2953 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2954 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2955 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2957 HBRUSH xBrush = whitePieceBrush;
\r
2958 tmpSize = squareSize;
\r
2959 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2961 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2962 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2963 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
2964 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
2965 x += (squareSize - minorSize)>>1;
\r
2966 y += squareSize - minorSize - 2;
\r
2967 tmpSize = minorSize;
\r
2969 if (color || appData.allWhite ) {
\r
2970 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2972 oldBrush = SelectObject(hdc, xBrush);
\r
2973 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
2974 if(appData.upsideDown && color==flipView)
\r
2975 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2977 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2978 /* Use black for outline of white pieces */
\r
2979 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
2980 if(appData.upsideDown && color==flipView)
\r
2981 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2983 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2984 } else if(appData.pieceDirectory[0]) {
\r
2985 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
2986 oldBrush = SelectObject(hdc, xBrush);
\r
2987 if(appData.upsideDown && color==flipView)
\r
2988 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
2990 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
2991 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2992 if(appData.upsideDown && color==flipView)
\r
2993 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
2995 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
2997 /* Use square color for details of black pieces */
\r
2998 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
2999 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3000 if(appData.upsideDown && !flipView)
\r
3001 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3003 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3005 SelectObject(hdc, oldBrush);
\r
3006 SelectObject(tmphdc, oldBitmap);
\r
3010 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3011 int GetBackTextureMode( int algo )
\r
3013 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3017 case BACK_TEXTURE_MODE_PLAIN:
\r
3018 result = 1; /* Always use identity map */
\r
3020 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3021 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3029 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3030 to handle redraws cleanly (as random numbers would always be different).
\r
3032 VOID RebuildTextureSquareInfo()
\r
3042 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3044 if( liteBackTexture != NULL ) {
\r
3045 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3046 lite_w = bi.bmWidth;
\r
3047 lite_h = bi.bmHeight;
\r
3051 if( darkBackTexture != NULL ) {
\r
3052 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3053 dark_w = bi.bmWidth;
\r
3054 dark_h = bi.bmHeight;
\r
3058 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3059 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3060 if( (col + row) & 1 ) {
\r
3062 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3063 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3064 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3066 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3067 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3068 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3070 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3071 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3076 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3077 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3078 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3080 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3081 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3082 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3084 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3085 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3092 /* [AS] Arrow highlighting support */
\r
3094 static double A_WIDTH = 5; /* Width of arrow body */
\r
3096 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3097 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3099 static double Sqr( double x )
\r
3104 static int Round( double x )
\r
3106 return (int) (x + 0.5);
\r
3109 /* Draw an arrow between two points using current settings */
\r
3110 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3113 double dx, dy, j, k, x, y;
\r
3115 if( d_x == s_x ) {
\r
3116 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3118 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3121 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3122 arrow[1].y = d_y - h;
\r
3124 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3125 arrow[2].y = d_y - h;
\r
3130 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3131 arrow[5].y = d_y - h;
\r
3133 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3134 arrow[4].y = d_y - h;
\r
3136 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3139 else if( d_y == s_y ) {
\r
3140 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3143 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3145 arrow[1].x = d_x - w;
\r
3146 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3148 arrow[2].x = d_x - w;
\r
3149 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3154 arrow[5].x = d_x - w;
\r
3155 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3157 arrow[4].x = d_x - w;
\r
3158 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3161 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3164 /* [AS] Needed a lot of paper for this! :-) */
\r
3165 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3166 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3168 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3170 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3175 arrow[0].x = Round(x - j);
\r
3176 arrow[0].y = Round(y + j*dx);
\r
3178 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3179 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3182 x = (double) d_x - k;
\r
3183 y = (double) d_y - k*dy;
\r
3186 x = (double) d_x + k;
\r
3187 y = (double) d_y + k*dy;
\r
3190 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3192 arrow[6].x = Round(x - j);
\r
3193 arrow[6].y = Round(y + j*dx);
\r
3195 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3196 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3198 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3199 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3204 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3205 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3208 Polygon( hdc, arrow, 7 );
\r
3211 /* [AS] Draw an arrow between two squares */
\r
3212 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3214 int s_x, s_y, d_x, d_y;
\r
3221 if( s_col == d_col && s_row == d_row ) {
\r
3225 /* Get source and destination points */
\r
3226 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3227 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3230 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3232 else if( d_y < s_y ) {
\r
3233 d_y += squareSize / 2 + squareSize / 4;
\r
3236 d_y += squareSize / 2;
\r
3240 d_x += squareSize / 2 - squareSize / 4;
\r
3242 else if( d_x < s_x ) {
\r
3243 d_x += squareSize / 2 + squareSize / 4;
\r
3246 d_x += squareSize / 2;
\r
3249 s_x += squareSize / 2;
\r
3250 s_y += squareSize / 2;
\r
3252 /* Adjust width */
\r
3253 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3256 stLB.lbStyle = BS_SOLID;
\r
3257 stLB.lbColor = appData.highlightArrowColor;
\r
3260 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3261 holdpen = SelectObject( hdc, hpen );
\r
3262 hbrush = CreateBrushIndirect( &stLB );
\r
3263 holdbrush = SelectObject( hdc, hbrush );
\r
3265 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3267 SelectObject( hdc, holdpen );
\r
3268 SelectObject( hdc, holdbrush );
\r
3269 DeleteObject( hpen );
\r
3270 DeleteObject( hbrush );
\r
3273 BOOL HasHighlightInfo()
\r
3275 BOOL result = FALSE;
\r
3277 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3278 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3289 BOOL IsDrawArrowEnabled()
\r
3291 BOOL result = FALSE;
\r
3293 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3300 VOID DrawArrowHighlight( HDC hdc )
\r
3302 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3303 DrawArrowBetweenSquares( hdc,
\r
3304 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3305 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3309 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3311 HRGN result = NULL;
\r
3313 if( HasHighlightInfo() ) {
\r
3314 int x1, y1, x2, y2;
\r
3315 int sx, sy, dx, dy;
\r
3317 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3318 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3320 sx = MIN( x1, x2 );
\r
3321 sy = MIN( y1, y2 );
\r
3322 dx = MAX( x1, x2 ) + squareSize;
\r
3323 dy = MAX( y1, y2 ) + squareSize;
\r
3325 result = CreateRectRgn( sx, sy, dx, dy );
\r
3332 Warning: this function modifies the behavior of several other functions.
\r
3334 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3335 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3336 repaint is scattered all over the place, which is not good for features such as
\r
3337 "arrow highlighting" that require a full repaint of the board.
\r
3339 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3340 user interaction, when speed is not so important) but especially to avoid errors
\r
3341 in the displayed graphics.
\r
3343 In such patched places, I always try refer to this function so there is a single
\r
3344 place to maintain knowledge.
\r
3346 To restore the original behavior, just return FALSE unconditionally.
\r
3348 BOOL IsFullRepaintPreferrable()
\r
3350 BOOL result = FALSE;
\r
3352 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3353 /* Arrow may appear on the board */
\r
3361 This function is called by DrawPosition to know whether a full repaint must
\r
3364 Only DrawPosition may directly call this function, which makes use of
\r
3365 some state information. Other function should call DrawPosition specifying
\r
3366 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3368 BOOL DrawPositionNeedsFullRepaint()
\r
3370 BOOL result = FALSE;
\r
3373 Probably a slightly better policy would be to trigger a full repaint
\r
3374 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3375 but animation is fast enough that it's difficult to notice.
\r
3377 if( animInfo.piece == EmptySquare ) {
\r
3378 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3386 static HBITMAP borderBitmap;
\r
3389 DrawBackgroundOnDC(HDC hdc)
\r
3395 static char oldBorder[MSG_SIZ];
\r
3396 int w = 600, h = 600, mode;
\r
3398 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3399 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3400 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3402 if(borderBitmap == NULL) { // loading failed, use white
\r
3403 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3406 tmphdc = CreateCompatibleDC(hdc);
\r
3407 hbm = SelectObject(tmphdc, borderBitmap);
\r
3408 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3412 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3413 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3414 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3415 SetStretchBltMode(hdc, mode);
\r
3416 SelectObject(tmphdc, hbm);
\r
3421 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3423 int row, column, x, y, square_color, piece_color;
\r
3424 ChessSquare piece;
\r
3426 HDC texture_hdc = NULL;
\r
3428 /* [AS] Initialize background textures if needed */
\r
3429 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3430 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3431 if( backTextureSquareSize != squareSize
\r
3432 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3433 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3434 backTextureSquareSize = squareSize;
\r
3435 RebuildTextureSquareInfo();
\r
3438 texture_hdc = CreateCompatibleDC( hdc );
\r
3441 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3442 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3444 SquareToPos(row, column, &x, &y);
\r
3446 piece = board[row][column];
\r
3448 square_color = ((column + row) % 2) == 1;
\r
3449 if( gameInfo.variant == VariantXiangqi ) {
\r
3450 square_color = !InPalace(row, column);
\r
3451 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3452 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3454 piece_color = (int) piece < (int) BlackPawn;
\r
3457 /* [HGM] holdings file: light square or black */
\r
3458 if(column == BOARD_LEFT-2) {
\r
3459 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3462 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3466 if(column == BOARD_RGHT + 1 ) {
\r
3467 if( row < gameInfo.holdingsSize )
\r
3470 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3474 if(column == BOARD_LEFT-1 ) /* left align */
\r
3475 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3476 else if( column == BOARD_RGHT) /* right align */
\r
3477 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3478 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3480 if (appData.monoMode) {
\r
3481 if (piece == EmptySquare) {
\r
3482 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3483 square_color ? WHITENESS : BLACKNESS);
\r
3485 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3488 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3489 /* [AS] Draw the square using a texture bitmap */
\r
3490 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3491 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3492 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3495 squareSize, squareSize,
\r
3498 backTextureSquareInfo[r][c].mode,
\r
3499 backTextureSquareInfo[r][c].x,
\r
3500 backTextureSquareInfo[r][c].y );
\r
3502 SelectObject( texture_hdc, hbm );
\r
3504 if (piece != EmptySquare) {
\r
3505 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3509 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3511 oldBrush = SelectObject(hdc, brush );
\r
3512 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3513 SelectObject(hdc, oldBrush);
\r
3514 if (piece != EmptySquare)
\r
3515 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3520 if( texture_hdc != NULL ) {
\r
3521 DeleteDC( texture_hdc );
\r
3525 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3526 void fputDW(FILE *f, int x)
\r
3528 fputc(x & 255, f);
\r
3529 fputc(x>>8 & 255, f);
\r
3530 fputc(x>>16 & 255, f);
\r
3531 fputc(x>>24 & 255, f);
\r
3534 #define MAX_CLIPS 200 /* more than enough */
\r
3537 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3539 // HBITMAP bufferBitmap;
\r
3544 int w = 100, h = 50;
\r
3546 if(logo == NULL) {
\r
3547 if(!logoHeight) return;
\r
3548 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3550 // GetClientRect(hwndMain, &Rect);
\r
3551 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3552 // Rect.bottom-Rect.top+1);
\r
3553 tmphdc = CreateCompatibleDC(hdc);
\r
3554 hbm = SelectObject(tmphdc, logo);
\r
3555 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3559 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3560 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3561 SelectObject(tmphdc, hbm);
\r
3569 HDC hdc = GetDC(hwndMain);
\r
3570 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3571 if(appData.autoLogo) {
\r
3573 switch(gameMode) { // pick logos based on game mode
\r
3574 case IcsObserving:
\r
3575 whiteLogo = second.programLogo; // ICS logo
\r
3576 blackLogo = second.programLogo;
\r
3579 case IcsPlayingWhite:
\r
3580 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3581 blackLogo = second.programLogo; // ICS logo
\r
3583 case IcsPlayingBlack:
\r
3584 whiteLogo = second.programLogo; // ICS logo
\r
3585 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3587 case TwoMachinesPlay:
\r
3588 if(first.twoMachinesColor[0] == 'b') {
\r
3589 whiteLogo = second.programLogo;
\r
3590 blackLogo = first.programLogo;
\r
3593 case MachinePlaysWhite:
\r
3594 blackLogo = userLogo;
\r
3596 case MachinePlaysBlack:
\r
3597 whiteLogo = userLogo;
\r
3598 blackLogo = first.programLogo;
\r
3601 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3602 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3603 ReleaseDC(hwndMain, hdc);
\r
3608 UpdateLogos(int display)
\r
3609 { // called after loading new engine(s), in tourney or from menu
\r
3610 LoadLogo(&first, 0, FALSE);
\r
3611 LoadLogo(&second, 1, appData.icsActive);
\r
3612 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3613 if(display) DisplayLogos();
\r
3616 static HDC hdcSeek;
\r
3618 // [HGM] seekgraph
\r
3619 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3622 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3623 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3624 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3625 SelectObject( hdcSeek, hp );
\r
3628 // front-end wrapper for drawing functions to do rectangles
\r
3629 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3634 if (hdcSeek == NULL) {
\r
3635 hdcSeek = GetDC(hwndMain);
\r
3636 if (!appData.monoMode) {
\r
3637 SelectPalette(hdcSeek, hPal, FALSE);
\r
3638 RealizePalette(hdcSeek);
\r
3641 hp = SelectObject( hdcSeek, gridPen );
\r
3642 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3643 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3644 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3645 SelectObject( hdcSeek, hp );
\r
3648 // front-end wrapper for putting text in graph
\r
3649 void DrawSeekText(char *buf, int x, int y)
\r
3652 SetBkMode( hdcSeek, TRANSPARENT );
\r
3653 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3654 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3657 void DrawSeekDot(int x, int y, int color)
\r
3659 int square = color & 0x80;
\r
3660 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3661 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3664 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3665 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3667 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3668 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3669 SelectObject(hdcSeek, oldBrush);
\r
3672 void DrawSeekOpen()
\r
3676 void DrawSeekClose()
\r
3681 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3683 static Board lastReq[2], lastDrawn[2];
\r
3684 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3685 static int lastDrawnFlipView = 0;
\r
3686 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3687 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3690 HBITMAP bufferBitmap;
\r
3691 HBITMAP oldBitmap;
\r
3693 HRGN clips[MAX_CLIPS];
\r
3694 ChessSquare dragged_piece = EmptySquare;
\r
3695 int nr = twoBoards*partnerUp;
\r
3697 /* I'm undecided on this - this function figures out whether a full
\r
3698 * repaint is necessary on its own, so there's no real reason to have the
\r
3699 * caller tell it that. I think this can safely be set to FALSE - but
\r
3700 * if we trust the callers not to request full repaints unnessesarily, then
\r
3701 * we could skip some clipping work. In other words, only request a full
\r
3702 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3703 * gamestart and similar) --Hawk
\r
3705 Boolean fullrepaint = repaint;
\r
3707 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3709 if( DrawPositionNeedsFullRepaint() ) {
\r
3710 fullrepaint = TRUE;
\r
3713 if (board == NULL) {
\r
3714 if (!lastReqValid[nr]) {
\r
3717 board = lastReq[nr];
\r
3719 CopyBoard(lastReq[nr], board);
\r
3720 lastReqValid[nr] = 1;
\r
3723 if (doingSizing) {
\r
3727 if (IsIconic(hwndMain)) {
\r
3731 if (hdc == NULL) {
\r
3732 hdc = GetDC(hwndMain);
\r
3733 if (!appData.monoMode) {
\r
3734 SelectPalette(hdc, hPal, FALSE);
\r
3735 RealizePalette(hdc);
\r
3739 releaseDC = FALSE;
\r
3742 /* Create some work-DCs */
\r
3743 hdcmem = CreateCompatibleDC(hdc);
\r
3744 tmphdc = CreateCompatibleDC(hdc);
\r
3746 /* If dragging is in progress, we temporarely remove the piece */
\r
3747 /* [HGM] or temporarily decrease count if stacked */
\r
3748 /* !! Moved to before board compare !! */
\r
3749 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3750 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3751 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3752 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3753 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3755 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3756 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3757 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3759 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3762 /* Figure out which squares need updating by comparing the
\r
3763 * newest board with the last drawn board and checking if
\r
3764 * flipping has changed.
\r
3766 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3767 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3768 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3769 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3770 SquareToPos(row, column, &x, &y);
\r
3771 clips[num_clips++] =
\r
3772 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3776 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3777 for (i=0; i<2; i++) {
\r
3778 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3779 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3780 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3781 lastDrawnHighlight.sq[i].y >= 0) {
\r
3782 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3783 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3784 clips[num_clips++] =
\r
3785 CreateRectRgn(x - lineGap, y - lineGap,
\r
3786 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3788 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3789 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3790 clips[num_clips++] =
\r
3791 CreateRectRgn(x - lineGap, y - lineGap,
\r
3792 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3796 for (i=0; i<2; i++) {
\r
3797 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3798 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3799 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3800 lastDrawnPremove.sq[i].y >= 0) {
\r
3801 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3802 lastDrawnPremove.sq[i].x, &x, &y);
\r
3803 clips[num_clips++] =
\r
3804 CreateRectRgn(x - lineGap, y - lineGap,
\r
3805 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3807 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3808 premoveHighlightInfo.sq[i].y >= 0) {
\r
3809 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3810 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3811 clips[num_clips++] =
\r
3812 CreateRectRgn(x - lineGap, y - lineGap,
\r
3813 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3817 } else { // nr == 1
\r
3818 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3819 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3820 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3821 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3822 for (i=0; i<2; i++) {
\r
3823 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3824 partnerHighlightInfo.sq[i].y >= 0) {
\r
3825 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3826 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3827 clips[num_clips++] =
\r
3828 CreateRectRgn(x - lineGap, y - lineGap,
\r
3829 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3831 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3832 oldPartnerHighlight.sq[i].y >= 0) {
\r
3833 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3834 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3835 clips[num_clips++] =
\r
3836 CreateRectRgn(x - lineGap, y - lineGap,
\r
3837 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3842 fullrepaint = TRUE;
\r
3845 /* Create a buffer bitmap - this is the actual bitmap
\r
3846 * being written to. When all the work is done, we can
\r
3847 * copy it to the real DC (the screen). This avoids
\r
3848 * the problems with flickering.
\r
3850 GetClientRect(hwndMain, &Rect);
\r
3851 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3852 Rect.bottom-Rect.top+1);
\r
3853 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3854 if (!appData.monoMode) {
\r
3855 SelectPalette(hdcmem, hPal, FALSE);
\r
3858 /* Create clips for dragging */
\r
3859 if (!fullrepaint) {
\r
3860 if (dragInfo.from.x >= 0) {
\r
3861 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3862 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3864 if (dragInfo.start.x >= 0) {
\r
3865 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3866 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3868 if (dragInfo.pos.x >= 0) {
\r
3869 x = dragInfo.pos.x - squareSize / 2;
\r
3870 y = dragInfo.pos.y - squareSize / 2;
\r
3871 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3873 if (dragInfo.lastpos.x >= 0) {
\r
3874 x = dragInfo.lastpos.x - squareSize / 2;
\r
3875 y = dragInfo.lastpos.y - squareSize / 2;
\r
3876 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3880 /* Are we animating a move?
\r
3882 * - remove the piece from the board (temporarely)
\r
3883 * - calculate the clipping region
\r
3885 if (!fullrepaint) {
\r
3886 if (animInfo.piece != EmptySquare) {
\r
3887 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3888 x = boardRect.left + animInfo.lastpos.x;
\r
3889 y = boardRect.top + animInfo.lastpos.y;
\r
3890 x2 = boardRect.left + animInfo.pos.x;
\r
3891 y2 = boardRect.top + animInfo.pos.y;
\r
3892 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3893 /* Slight kludge. The real problem is that after AnimateMove is
\r
3894 done, the position on the screen does not match lastDrawn.
\r
3895 This currently causes trouble only on e.p. captures in
\r
3896 atomic, where the piece moves to an empty square and then
\r
3897 explodes. The old and new positions both had an empty square
\r
3898 at the destination, but animation has drawn a piece there and
\r
3899 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3900 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3904 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3905 if (num_clips == 0)
\r
3906 fullrepaint = TRUE;
\r
3908 /* Set clipping on the memory DC */
\r
3909 if (!fullrepaint) {
\r
3910 SelectClipRgn(hdcmem, clips[0]);
\r
3911 for (x = 1; x < num_clips; x++) {
\r
3912 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3913 abort(); // this should never ever happen!
\r
3917 /* Do all the drawing to the memory DC */
\r
3918 if(explodeInfo.radius) { // [HGM] atomic
\r
3920 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3921 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3922 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3923 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3924 x += squareSize/2;
\r
3925 y += squareSize/2;
\r
3926 if(!fullrepaint) {
\r
3927 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3928 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3930 DrawGridOnDC(hdcmem);
\r
3931 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3932 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3933 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3934 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3935 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3936 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3937 SelectObject(hdcmem, oldBrush);
\r
3939 if(border) DrawBackgroundOnDC(hdcmem);
\r
3940 DrawGridOnDC(hdcmem);
\r
3941 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3942 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3943 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3945 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3946 oldPartnerHighlight = partnerHighlightInfo;
\r
3948 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3950 if(nr == 0) // [HGM] dual: markers only on left board
\r
3951 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3952 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3953 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3954 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
3955 SquareToPos(row, column, &x, &y);
\r
3956 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3957 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3958 SelectObject(hdcmem, oldBrush);
\r
3963 if( appData.highlightMoveWithArrow ) {
\r
3964 DrawArrowHighlight(hdcmem);
\r
3967 DrawCoordsOnDC(hdcmem);
\r
3969 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
3970 /* to make sure lastDrawn contains what is actually drawn */
\r
3972 /* Put the dragged piece back into place and draw it (out of place!) */
\r
3973 if (dragged_piece != EmptySquare) {
\r
3974 /* [HGM] or restack */
\r
3975 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
3976 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
3978 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
3979 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
3980 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
3981 x = dragInfo.pos.x - squareSize / 2;
\r
3982 y = dragInfo.pos.y - squareSize / 2;
\r
3983 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
3984 ((int) dragInfo.piece < (int) BlackPawn),
\r
3985 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
3988 /* Put the animated piece back into place and draw it */
\r
3989 if (animInfo.piece != EmptySquare) {
\r
3990 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
3991 x = boardRect.left + animInfo.pos.x;
\r
3992 y = boardRect.top + animInfo.pos.y;
\r
3993 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
3994 ((int) animInfo.piece < (int) BlackPawn),
\r
3995 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
3998 /* Release the bufferBitmap by selecting in the old bitmap
\r
3999 * and delete the memory DC
\r
4001 SelectObject(hdcmem, oldBitmap);
\r
4004 /* Set clipping on the target DC */
\r
4005 if (!fullrepaint) {
\r
4006 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4008 GetRgnBox(clips[x], &rect);
\r
4009 DeleteObject(clips[x]);
\r
4010 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4011 rect.right + wpMain.width/2, rect.bottom);
\r
4013 SelectClipRgn(hdc, clips[0]);
\r
4014 for (x = 1; x < num_clips; x++) {
\r
4015 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4016 abort(); // this should never ever happen!
\r
4020 /* Copy the new bitmap onto the screen in one go.
\r
4021 * This way we avoid any flickering
\r
4023 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4024 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4025 boardRect.right - boardRect.left,
\r
4026 boardRect.bottom - boardRect.top,
\r
4027 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4028 if(saveDiagFlag) {
\r
4029 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4030 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4032 GetObject(bufferBitmap, sizeof(b), &b);
\r
4033 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4034 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4035 bih.biWidth = b.bmWidth;
\r
4036 bih.biHeight = b.bmHeight;
\r
4038 bih.biBitCount = b.bmBitsPixel;
\r
4039 bih.biCompression = 0;
\r
4040 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4041 bih.biXPelsPerMeter = 0;
\r
4042 bih.biYPelsPerMeter = 0;
\r
4043 bih.biClrUsed = 0;
\r
4044 bih.biClrImportant = 0;
\r
4045 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4046 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4047 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4048 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4050 wb = b.bmWidthBytes;
\r
4052 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4053 int k = ((int*) pData)[i];
\r
4054 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4055 if(j >= 16) break;
\r
4057 if(j >= nrColors) nrColors = j+1;
\r
4059 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4061 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4062 for(w=0; w<(wb>>2); w+=2) {
\r
4063 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4064 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4065 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4066 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4067 pData[p++] = m | j<<4;
\r
4069 while(p&3) pData[p++] = 0;
\r
4072 wb = ((wb+31)>>5)<<2;
\r
4074 // write BITMAPFILEHEADER
\r
4075 fprintf(diagFile, "BM");
\r
4076 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4077 fputDW(diagFile, 0);
\r
4078 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4079 // write BITMAPINFOHEADER
\r
4080 fputDW(diagFile, 40);
\r
4081 fputDW(diagFile, b.bmWidth);
\r
4082 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4083 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4084 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4085 fputDW(diagFile, 0);
\r
4086 fputDW(diagFile, 0);
\r
4087 fputDW(diagFile, 0);
\r
4088 fputDW(diagFile, 0);
\r
4089 fputDW(diagFile, 0);
\r
4090 fputDW(diagFile, 0);
\r
4091 // write color table
\r
4093 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4094 // write bitmap data
\r
4095 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4096 fputc(pData[i], diagFile);
\r
4101 SelectObject(tmphdc, oldBitmap);
\r
4103 /* Massive cleanup */
\r
4104 for (x = 0; x < num_clips; x++)
\r
4105 DeleteObject(clips[x]);
\r
4108 DeleteObject(bufferBitmap);
\r
4111 ReleaseDC(hwndMain, hdc);
\r
4113 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4115 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4117 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4120 /* CopyBoard(lastDrawn, board);*/
\r
4121 lastDrawnHighlight = highlightInfo;
\r
4122 lastDrawnPremove = premoveHighlightInfo;
\r
4123 lastDrawnFlipView = flipView;
\r
4124 lastDrawnValid[nr] = 1;
\r
4127 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4132 saveDiagFlag = 1; diagFile = f;
\r
4133 HDCDrawPosition(NULL, TRUE, NULL);
\r
4141 /*---------------------------------------------------------------------------*\
\r
4142 | CLIENT PAINT PROCEDURE
\r
4143 | This is the main event-handler for the WM_PAINT message.
\r
4145 \*---------------------------------------------------------------------------*/
\r
4147 PaintProc(HWND hwnd)
\r
4153 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4154 if (IsIconic(hwnd)) {
\r
4155 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4157 if (!appData.monoMode) {
\r
4158 SelectPalette(hdc, hPal, FALSE);
\r
4159 RealizePalette(hdc);
\r
4161 HDCDrawPosition(hdc, 1, NULL);
\r
4162 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4163 flipView = !flipView; partnerUp = !partnerUp;
\r
4164 HDCDrawPosition(hdc, 1, NULL);
\r
4165 flipView = !flipView; partnerUp = !partnerUp;
\r
4168 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4169 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4170 ETO_CLIPPED|ETO_OPAQUE,
\r
4171 &messageRect, messageText, strlen(messageText), NULL);
\r
4172 SelectObject(hdc, oldFont);
\r
4173 DisplayBothClocks();
\r
4176 EndPaint(hwnd,&ps);
\r
4184 * If the user selects on a border boundary, return -1; if off the board,
\r
4185 * return -2. Otherwise map the event coordinate to the square.
\r
4186 * The offset boardRect.left or boardRect.top must already have been
\r
4187 * subtracted from x.
\r
4189 int EventToSquare(x, limit)
\r
4194 if (x < lineGap + border)
\r
4196 x -= lineGap + border;
\r
4197 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4199 x /= (squareSize + lineGap);
\r
4211 DropEnable dropEnables[] = {
\r
4212 { 'P', DP_Pawn, N_("Pawn") },
\r
4213 { 'N', DP_Knight, N_("Knight") },
\r
4214 { 'B', DP_Bishop, N_("Bishop") },
\r
4215 { 'R', DP_Rook, N_("Rook") },
\r
4216 { 'Q', DP_Queen, N_("Queen") },
\r
4220 SetupDropMenu(HMENU hmenu)
\r
4222 int i, count, enable;
\r
4224 extern char white_holding[], black_holding[];
\r
4225 char item[MSG_SIZ];
\r
4227 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4228 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4229 dropEnables[i].piece);
\r
4231 while (p && *p++ == dropEnables[i].piece) count++;
\r
4232 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4233 enable = count > 0 || !appData.testLegality
\r
4234 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4235 && !appData.icsActive);
\r
4236 ModifyMenu(hmenu, dropEnables[i].command,
\r
4237 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4238 dropEnables[i].command, item);
\r
4242 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4244 dragInfo.lastpos.x = boardRect.left + x;
\r
4245 dragInfo.lastpos.y = boardRect.top + y;
\r
4246 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4247 dragInfo.from.x = fromX;
\r
4248 dragInfo.from.y = fromY;
\r
4249 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4250 dragInfo.start = dragInfo.from;
\r
4251 SetCapture(hwndMain);
\r
4254 void DragPieceEnd(int x, int y)
\r
4257 dragInfo.start.x = dragInfo.start.y = -1;
\r
4258 dragInfo.from = dragInfo.start;
\r
4259 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4262 void ChangeDragPiece(ChessSquare piece)
\r
4264 dragInfo.piece = piece;
\r
4267 /* Event handler for mouse messages */
\r
4269 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4273 static int recursive = 0;
\r
4275 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4278 if (message == WM_MBUTTONUP) {
\r
4279 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4280 to the middle button: we simulate pressing the left button too!
\r
4282 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4283 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4289 pt.x = LOWORD(lParam);
\r
4290 pt.y = HIWORD(lParam);
\r
4291 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4292 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4293 if (!flipView && y >= 0) {
\r
4294 y = BOARD_HEIGHT - 1 - y;
\r
4296 if (flipView && x >= 0) {
\r
4297 x = BOARD_WIDTH - 1 - x;
\r
4300 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4301 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4303 switch (message) {
\r
4304 case WM_LBUTTONDOWN:
\r
4305 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4306 ClockClick(flipClock); break;
\r
4307 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4308 ClockClick(!flipClock); break;
\r
4310 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4311 dragInfo.start.x = dragInfo.start.y = -1;
\r
4312 dragInfo.from = dragInfo.start;
\r
4314 if(fromX == -1 && frozen) { // not sure where this is for
\r
4315 fromX = fromY = -1;
\r
4316 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4319 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4320 DrawPosition(TRUE, NULL);
\r
4323 case WM_LBUTTONUP:
\r
4324 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4325 DrawPosition(TRUE, NULL);
\r
4328 case WM_MOUSEMOVE:
\r
4329 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4330 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4331 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4332 if ((appData.animateDragging || appData.highlightDragging)
\r
4333 && (wParam & MK_LBUTTON || dragging == 2)
\r
4334 && dragInfo.from.x >= 0)
\r
4336 BOOL full_repaint = FALSE;
\r
4338 if (appData.animateDragging) {
\r
4339 dragInfo.pos = pt;
\r
4341 if (appData.highlightDragging) {
\r
4342 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4343 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4344 full_repaint = TRUE;
\r
4348 DrawPosition( full_repaint, NULL);
\r
4350 dragInfo.lastpos = dragInfo.pos;
\r
4354 case WM_MOUSEWHEEL: // [DM]
\r
4355 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4356 /* Mouse Wheel is being rolled forward
\r
4357 * Play moves forward
\r
4359 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4360 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4361 /* Mouse Wheel is being rolled backward
\r
4362 * Play moves backward
\r
4364 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4365 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4369 case WM_MBUTTONUP:
\r
4370 case WM_RBUTTONUP:
\r
4372 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4375 case WM_MBUTTONDOWN:
\r
4376 case WM_RBUTTONDOWN:
\r
4379 fromX = fromY = -1;
\r
4380 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4381 dragInfo.start.x = dragInfo.start.y = -1;
\r
4382 dragInfo.from = dragInfo.start;
\r
4383 dragInfo.lastpos = dragInfo.pos;
\r
4384 if (appData.highlightDragging) {
\r
4385 ClearHighlights();
\r
4388 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4389 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4390 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4391 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4392 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4396 DrawPosition(TRUE, NULL);
\r
4398 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4401 if (message == WM_MBUTTONDOWN) {
\r
4402 buttonCount = 3; /* even if system didn't think so */
\r
4403 if (wParam & MK_SHIFT)
\r
4404 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4406 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4407 } else { /* message == WM_RBUTTONDOWN */
\r
4408 /* Just have one menu, on the right button. Windows users don't
\r
4409 think to try the middle one, and sometimes other software steals
\r
4410 it, or it doesn't really exist. */
\r
4411 if(gameInfo.variant != VariantShogi)
\r
4412 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4414 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4418 SetCapture(hwndMain);
\r
4421 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4422 SetupDropMenu(hmenu);
\r
4423 MenuPopup(hwnd, pt, hmenu, -1);
\r
4433 /* Preprocess messages for buttons in main window */
\r
4435 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4437 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4440 for (i=0; i<N_BUTTONS; i++) {
\r
4441 if (buttonDesc[i].id == id) break;
\r
4443 if (i == N_BUTTONS) return 0;
\r
4444 switch (message) {
\r
4449 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4450 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4457 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4460 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4461 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4462 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4463 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4465 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4467 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4468 TypeInEvent((char)wParam);
\r
4474 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4477 static int promoStyle;
\r
4479 /* Process messages for Promotion dialog box */
\r
4481 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4485 switch (message) {
\r
4486 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4487 /* Center the dialog over the application window */
\r
4488 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4489 Translate(hDlg, DLG_PromotionKing);
\r
4490 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4491 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4492 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4493 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4494 SW_SHOW : SW_HIDE);
\r
4495 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4496 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4497 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4498 PieceToChar(WhiteAngel) != '~') ||
\r
4499 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4500 PieceToChar(BlackAngel) != '~') ) ?
\r
4501 SW_SHOW : SW_HIDE);
\r
4502 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4503 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4504 PieceToChar(WhiteMarshall) != '~') ||
\r
4505 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4506 PieceToChar(BlackMarshall) != '~') ) ?
\r
4507 SW_SHOW : SW_HIDE);
\r
4508 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4509 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4510 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4512 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4513 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4514 SetWindowText(hDlg, "Promote?");
\r
4516 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4517 gameInfo.variant == VariantSuper ?
\r
4518 SW_SHOW : SW_HIDE);
\r
4521 case WM_COMMAND: /* message: received a command */
\r
4522 switch (LOWORD(wParam)) {
\r
4524 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4525 ClearHighlights();
\r
4526 DrawPosition(FALSE, NULL);
\r
4529 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4532 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4535 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4536 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4539 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4540 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4542 case PB_Chancellor:
\r
4543 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4545 case PB_Archbishop:
\r
4546 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4549 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4550 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4555 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4556 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4557 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4558 fromX = fromY = -1;
\r
4559 if (!appData.highlightLastMove) {
\r
4560 ClearHighlights();
\r
4561 DrawPosition(FALSE, NULL);
\r
4568 /* Pop up promotion dialog */
\r
4570 PromotionPopup(HWND hwnd)
\r
4574 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4575 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4576 hwnd, (DLGPROC)lpProc);
\r
4577 FreeProcInstance(lpProc);
\r
4581 PromotionPopUp(char choice)
\r
4583 promoStyle = (choice == '+');
\r
4584 DrawPosition(TRUE, NULL);
\r
4585 PromotionPopup(hwndMain);
\r
4589 LoadGameDialog(HWND hwnd, char* title)
\r
4593 char fileTitle[MSG_SIZ];
\r
4594 f = OpenFileDialog(hwnd, "rb", "",
\r
4595 appData.oldSaveStyle ? "gam" : "pgn",
\r
4597 title, &number, fileTitle, NULL);
\r
4599 cmailMsgLoaded = FALSE;
\r
4600 if (number == 0) {
\r
4601 int error = GameListBuild(f);
\r
4603 DisplayError(_("Cannot build game list"), error);
\r
4604 } else if (!ListEmpty(&gameList) &&
\r
4605 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4606 GameListPopUp(f, fileTitle);
\r
4609 GameListDestroy();
\r
4612 LoadGame(f, number, fileTitle, FALSE);
\r
4616 int get_term_width()
\r
4621 HFONT hfont, hold_font;
\r
4626 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4630 // get the text metrics
\r
4631 hdc = GetDC(hText);
\r
4632 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4633 if (consoleCF.dwEffects & CFE_BOLD)
\r
4634 lf.lfWeight = FW_BOLD;
\r
4635 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4636 lf.lfItalic = TRUE;
\r
4637 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4638 lf.lfStrikeOut = TRUE;
\r
4639 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4640 lf.lfUnderline = TRUE;
\r
4641 hfont = CreateFontIndirect(&lf);
\r
4642 hold_font = SelectObject(hdc, hfont);
\r
4643 GetTextMetrics(hdc, &tm);
\r
4644 SelectObject(hdc, hold_font);
\r
4645 DeleteObject(hfont);
\r
4646 ReleaseDC(hText, hdc);
\r
4648 // get the rectangle
\r
4649 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4651 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4654 void UpdateICSWidth(HWND hText)
\r
4656 LONG old_width, new_width;
\r
4658 new_width = get_term_width(hText, FALSE);
\r
4659 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4660 if (new_width != old_width)
\r
4662 ics_update_width(new_width);
\r
4663 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4668 ChangedConsoleFont()
\r
4671 CHARRANGE tmpsel, sel;
\r
4672 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4673 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4674 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4677 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4678 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4679 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4680 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4681 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4682 * size. This was undocumented in the version of MSVC++ that I had
\r
4683 * when I wrote the code, but is apparently documented now.
\r
4685 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4686 cfmt.bCharSet = f->lf.lfCharSet;
\r
4687 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4688 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4689 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4690 /* Why are the following seemingly needed too? */
\r
4691 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4692 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4693 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4695 tmpsel.cpMax = -1; /*999999?*/
\r
4696 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4697 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4698 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4699 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4701 paraf.cbSize = sizeof(paraf);
\r
4702 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4703 paraf.dxStartIndent = 0;
\r
4704 paraf.dxOffset = WRAP_INDENT;
\r
4705 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4706 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4707 UpdateICSWidth(hText);
\r
4710 /*---------------------------------------------------------------------------*\
\r
4712 * Window Proc for main window
\r
4714 \*---------------------------------------------------------------------------*/
\r
4716 /* Process messages for main window, etc. */
\r
4718 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4721 int wmId, wmEvent;
\r
4725 char fileTitle[MSG_SIZ];
\r
4726 static SnapData sd;
\r
4727 static int peek=0;
\r
4729 switch (message) {
\r
4731 case WM_PAINT: /* message: repaint portion of window */
\r
4735 case WM_ERASEBKGND:
\r
4736 if (IsIconic(hwnd)) {
\r
4737 /* Cheat; change the message */
\r
4738 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4740 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4744 case WM_LBUTTONDOWN:
\r
4745 case WM_MBUTTONDOWN:
\r
4746 case WM_RBUTTONDOWN:
\r
4747 case WM_LBUTTONUP:
\r
4748 case WM_MBUTTONUP:
\r
4749 case WM_RBUTTONUP:
\r
4750 case WM_MOUSEMOVE:
\r
4751 case WM_MOUSEWHEEL:
\r
4752 MouseEvent(hwnd, message, wParam, lParam);
\r
4756 if((char)wParam == '\b') {
\r
4757 ForwardEvent(); peek = 0;
\r
4760 JAWS_KBUP_NAVIGATION
\r
4765 if((char)wParam == '\b') {
\r
4766 if(!peek) BackwardEvent(), peek = 1;
\r
4769 JAWS_KBDOWN_NAVIGATION
\r
4775 JAWS_ALT_INTERCEPT
\r
4777 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4778 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4779 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4780 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4782 SendMessage(h, message, wParam, lParam);
\r
4783 } else if(lParam != KF_REPEAT) {
\r
4784 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4785 TypeInEvent((char)wParam);
\r
4786 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4787 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4792 case WM_PALETTECHANGED:
\r
4793 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4795 HDC hdc = GetDC(hwndMain);
\r
4796 SelectPalette(hdc, hPal, TRUE);
\r
4797 nnew = RealizePalette(hdc);
\r
4799 paletteChanged = TRUE;
\r
4801 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4803 ReleaseDC(hwnd, hdc);
\r
4807 case WM_QUERYNEWPALETTE:
\r
4808 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4810 HDC hdc = GetDC(hwndMain);
\r
4811 paletteChanged = FALSE;
\r
4812 SelectPalette(hdc, hPal, FALSE);
\r
4813 nnew = RealizePalette(hdc);
\r
4815 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4817 ReleaseDC(hwnd, hdc);
\r
4822 case WM_COMMAND: /* message: command from application menu */
\r
4823 wmId = LOWORD(wParam);
\r
4824 wmEvent = HIWORD(wParam);
\r
4829 SAY("new game enter a move to play against the computer with white");
\r
4832 case IDM_NewGameFRC:
\r
4833 if( NewGameFRC() == 0 ) {
\r
4838 case IDM_NewVariant:
\r
4839 NewVariantPopup(hwnd);
\r
4842 case IDM_LoadGame:
\r
4843 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4846 case IDM_LoadNextGame:
\r
4850 case IDM_LoadPrevGame:
\r
4854 case IDM_ReloadGame:
\r
4858 case IDM_LoadPosition:
\r
4859 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4860 Reset(FALSE, TRUE);
\r
4863 f = OpenFileDialog(hwnd, "rb", "",
\r
4864 appData.oldSaveStyle ? "pos" : "fen",
\r
4866 _("Load Position from File"), &number, fileTitle, NULL);
\r
4868 LoadPosition(f, number, fileTitle);
\r
4872 case IDM_LoadNextPosition:
\r
4873 ReloadPosition(1);
\r
4876 case IDM_LoadPrevPosition:
\r
4877 ReloadPosition(-1);
\r
4880 case IDM_ReloadPosition:
\r
4881 ReloadPosition(0);
\r
4884 case IDM_SaveGame:
\r
4885 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4886 f = OpenFileDialog(hwnd, "a", defName,
\r
4887 appData.oldSaveStyle ? "gam" : "pgn",
\r
4889 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4891 SaveGame(f, 0, "");
\r
4895 case IDM_SavePosition:
\r
4896 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4897 f = OpenFileDialog(hwnd, "a", defName,
\r
4898 appData.oldSaveStyle ? "pos" : "fen",
\r
4900 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4902 SavePosition(f, 0, "");
\r
4906 case IDM_SaveDiagram:
\r
4907 defName = "diagram";
\r
4908 f = OpenFileDialog(hwnd, "wb", defName,
\r
4911 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4917 case IDM_CreateBook:
\r
4918 CreateBookEvent();
\r
4921 case IDM_CopyGame:
\r
4922 CopyGameToClipboard();
\r
4925 case IDM_PasteGame:
\r
4926 PasteGameFromClipboard();
\r
4929 case IDM_CopyGameListToClipboard:
\r
4930 CopyGameListToClipboard();
\r
4933 /* [AS] Autodetect FEN or PGN data */
\r
4934 case IDM_PasteAny:
\r
4935 PasteGameOrFENFromClipboard();
\r
4938 /* [AS] Move history */
\r
4939 case IDM_ShowMoveHistory:
\r
4940 if( MoveHistoryIsUp() ) {
\r
4941 MoveHistoryPopDown();
\r
4944 MoveHistoryPopUp();
\r
4948 /* [AS] Eval graph */
\r
4949 case IDM_ShowEvalGraph:
\r
4950 if( EvalGraphIsUp() ) {
\r
4951 EvalGraphPopDown();
\r
4955 SetFocus(hwndMain);
\r
4959 /* [AS] Engine output */
\r
4960 case IDM_ShowEngineOutput:
\r
4961 if( EngineOutputIsUp() ) {
\r
4962 EngineOutputPopDown();
\r
4965 EngineOutputPopUp();
\r
4969 /* [AS] User adjudication */
\r
4970 case IDM_UserAdjudication_White:
\r
4971 UserAdjudicationEvent( +1 );
\r
4974 case IDM_UserAdjudication_Black:
\r
4975 UserAdjudicationEvent( -1 );
\r
4978 case IDM_UserAdjudication_Draw:
\r
4979 UserAdjudicationEvent( 0 );
\r
4982 /* [AS] Game list options dialog */
\r
4983 case IDM_GameListOptions:
\r
4984 GameListOptions();
\r
4991 case IDM_CopyPosition:
\r
4992 CopyFENToClipboard();
\r
4995 case IDM_PastePosition:
\r
4996 PasteFENFromClipboard();
\r
4999 case IDM_MailMove:
\r
5003 case IDM_ReloadCMailMsg:
\r
5004 Reset(TRUE, TRUE);
\r
5005 ReloadCmailMsgEvent(FALSE);
\r
5008 case IDM_Minimize:
\r
5009 ShowWindow(hwnd, SW_MINIMIZE);
\r
5016 case IDM_MachineWhite:
\r
5017 MachineWhiteEvent();
\r
5019 * refresh the tags dialog only if it's visible
\r
5021 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5023 tags = PGNTags(&gameInfo);
\r
5024 TagsPopUp(tags, CmailMsg());
\r
5027 SAY("computer starts playing white");
\r
5030 case IDM_MachineBlack:
\r
5031 MachineBlackEvent();
\r
5033 * refresh the tags dialog only if it's visible
\r
5035 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5037 tags = PGNTags(&gameInfo);
\r
5038 TagsPopUp(tags, CmailMsg());
\r
5041 SAY("computer starts playing black");
\r
5044 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5045 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5048 case IDM_TwoMachines:
\r
5049 TwoMachinesEvent();
\r
5051 * refresh the tags dialog only if it's visible
\r
5053 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5055 tags = PGNTags(&gameInfo);
\r
5056 TagsPopUp(tags, CmailMsg());
\r
5059 SAY("computer starts playing both sides");
\r
5062 case IDM_AnalysisMode:
\r
5063 if(AnalyzeModeEvent()) {
\r
5064 SAY("analyzing current position");
\r
5068 case IDM_AnalyzeFile:
\r
5069 AnalyzeFileEvent();
\r
5072 case IDM_IcsClient:
\r
5076 case IDM_EditGame:
\r
5077 case IDM_EditGame2:
\r
5082 case IDM_EditPosition:
\r
5083 case IDM_EditPosition2:
\r
5084 EditPositionEvent();
\r
5085 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5088 case IDM_Training:
\r
5092 case IDM_ShowGameList:
\r
5093 ShowGameListProc();
\r
5096 case IDM_EditProgs1:
\r
5097 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5100 case IDM_LoadProg1:
\r
5101 LoadEnginePopUp(hwndMain, 0);
\r
5104 case IDM_LoadProg2:
\r
5105 LoadEnginePopUp(hwndMain, 1);
\r
5108 case IDM_EditServers:
\r
5109 EditTagsPopUp(icsNames, &icsNames);
\r
5112 case IDM_EditTags:
\r
5117 case IDM_EditBook:
\r
5121 case IDM_EditComment:
\r
5123 if (commentUp && editComment) {
\r
5126 EditCommentEvent();
\r
5147 case IDM_CallFlag:
\r
5167 case IDM_StopObserving:
\r
5168 StopObservingEvent();
\r
5171 case IDM_StopExamining:
\r
5172 StopExaminingEvent();
\r
5176 UploadGameEvent();
\r
5179 case IDM_TypeInMove:
\r
5180 TypeInEvent('\000');
\r
5183 case IDM_TypeInName:
\r
5184 PopUpNameDialog('\000');
\r
5187 case IDM_Backward:
\r
5189 SetFocus(hwndMain);
\r
5196 SetFocus(hwndMain);
\r
5201 SetFocus(hwndMain);
\r
5206 SetFocus(hwndMain);
\r
5209 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5210 case OPT_GameListPrev:
\r
5211 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5215 RevertEvent(FALSE);
\r
5218 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5219 RevertEvent(TRUE);
\r
5222 case IDM_TruncateGame:
\r
5223 TruncateGameEvent();
\r
5230 case IDM_RetractMove:
\r
5231 RetractMoveEvent();
\r
5234 case IDM_FlipView:
\r
5235 flipView = !flipView;
\r
5236 DrawPosition(FALSE, NULL);
\r
5239 case IDM_FlipClock:
\r
5240 flipClock = !flipClock;
\r
5241 DisplayBothClocks();
\r
5245 case IDM_MuteSounds:
\r
5246 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5247 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5248 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5251 case IDM_GeneralOptions:
\r
5252 GeneralOptionsPopup(hwnd);
\r
5253 DrawPosition(TRUE, NULL);
\r
5256 case IDM_BoardOptions:
\r
5257 BoardOptionsPopup(hwnd);
\r
5260 case IDM_ThemeOptions:
\r
5261 ThemeOptionsPopup(hwnd);
\r
5264 case IDM_EnginePlayOptions:
\r
5265 EnginePlayOptionsPopup(hwnd);
\r
5268 case IDM_Engine1Options:
\r
5269 EngineOptionsPopup(hwnd, &first);
\r
5272 case IDM_Engine2Options:
\r
5274 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5275 EngineOptionsPopup(hwnd, &second);
\r
5278 case IDM_OptionsUCI:
\r
5279 UciOptionsPopup(hwnd);
\r
5283 TourneyPopup(hwnd);
\r
5286 case IDM_IcsOptions:
\r
5287 IcsOptionsPopup(hwnd);
\r
5291 FontsOptionsPopup(hwnd);
\r
5295 SoundOptionsPopup(hwnd);
\r
5298 case IDM_CommPort:
\r
5299 CommPortOptionsPopup(hwnd);
\r
5302 case IDM_LoadOptions:
\r
5303 LoadOptionsPopup(hwnd);
\r
5306 case IDM_SaveOptions:
\r
5307 SaveOptionsPopup(hwnd);
\r
5310 case IDM_TimeControl:
\r
5311 TimeControlOptionsPopup(hwnd);
\r
5314 case IDM_SaveSettings:
\r
5315 SaveSettings(settingsFileName);
\r
5318 case IDM_SaveSettingsOnExit:
\r
5319 saveSettingsOnExit = !saveSettingsOnExit;
\r
5320 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5321 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5322 MF_CHECKED : MF_UNCHECKED));
\r
5333 case IDM_AboutGame:
\r
5338 appData.debugMode = !appData.debugMode;
\r
5339 if (appData.debugMode) {
\r
5340 char dir[MSG_SIZ];
\r
5341 GetCurrentDirectory(MSG_SIZ, dir);
\r
5342 SetCurrentDirectory(installDir);
\r
5343 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5344 SetCurrentDirectory(dir);
\r
5345 setbuf(debugFP, NULL);
\r
5352 case IDM_HELPCONTENTS:
\r
5353 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5354 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5355 MessageBox (GetFocus(),
\r
5356 _("Unable to activate help"),
\r
5357 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5361 case IDM_HELPSEARCH:
\r
5362 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5363 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5364 MessageBox (GetFocus(),
\r
5365 _("Unable to activate help"),
\r
5366 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5370 case IDM_HELPHELP:
\r
5371 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5372 MessageBox (GetFocus(),
\r
5373 _("Unable to activate help"),
\r
5374 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5379 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5381 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5382 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5383 FreeProcInstance(lpProc);
\r
5386 case IDM_DirectCommand1:
\r
5387 AskQuestionEvent(_("Direct Command"),
\r
5388 _("Send to chess program:"), "", "1");
\r
5390 case IDM_DirectCommand2:
\r
5391 AskQuestionEvent(_("Direct Command"),
\r
5392 _("Send to second chess program:"), "", "2");
\r
5395 case EP_WhitePawn:
\r
5396 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5397 fromX = fromY = -1;
\r
5400 case EP_WhiteKnight:
\r
5401 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5402 fromX = fromY = -1;
\r
5405 case EP_WhiteBishop:
\r
5406 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5407 fromX = fromY = -1;
\r
5410 case EP_WhiteRook:
\r
5411 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5412 fromX = fromY = -1;
\r
5415 case EP_WhiteQueen:
\r
5416 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5417 fromX = fromY = -1;
\r
5420 case EP_WhiteFerz:
\r
5421 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5422 fromX = fromY = -1;
\r
5425 case EP_WhiteWazir:
\r
5426 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5427 fromX = fromY = -1;
\r
5430 case EP_WhiteAlfil:
\r
5431 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5432 fromX = fromY = -1;
\r
5435 case EP_WhiteCannon:
\r
5436 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5437 fromX = fromY = -1;
\r
5440 case EP_WhiteCardinal:
\r
5441 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5442 fromX = fromY = -1;
\r
5445 case EP_WhiteMarshall:
\r
5446 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5447 fromX = fromY = -1;
\r
5450 case EP_WhiteKing:
\r
5451 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5452 fromX = fromY = -1;
\r
5455 case EP_BlackPawn:
\r
5456 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5457 fromX = fromY = -1;
\r
5460 case EP_BlackKnight:
\r
5461 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5462 fromX = fromY = -1;
\r
5465 case EP_BlackBishop:
\r
5466 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5467 fromX = fromY = -1;
\r
5470 case EP_BlackRook:
\r
5471 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5472 fromX = fromY = -1;
\r
5475 case EP_BlackQueen:
\r
5476 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5477 fromX = fromY = -1;
\r
5480 case EP_BlackFerz:
\r
5481 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5482 fromX = fromY = -1;
\r
5485 case EP_BlackWazir:
\r
5486 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5487 fromX = fromY = -1;
\r
5490 case EP_BlackAlfil:
\r
5491 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5492 fromX = fromY = -1;
\r
5495 case EP_BlackCannon:
\r
5496 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5497 fromX = fromY = -1;
\r
5500 case EP_BlackCardinal:
\r
5501 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5502 fromX = fromY = -1;
\r
5505 case EP_BlackMarshall:
\r
5506 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5507 fromX = fromY = -1;
\r
5510 case EP_BlackKing:
\r
5511 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5512 fromX = fromY = -1;
\r
5515 case EP_EmptySquare:
\r
5516 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5520 case EP_ClearBoard:
\r
5521 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5522 fromX = fromY = -1;
\r
5526 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5527 fromX = fromY = -1;
\r
5531 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5532 fromX = fromY = -1;
\r
5536 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5537 fromX = fromY = -1;
\r
5541 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5542 fromX = fromY = -1;
\r
5546 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5547 fromX = fromY = -1;
\r
5551 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5552 fromX = fromY = -1;
\r
5556 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5557 fromX = fromY = -1;
\r
5561 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5562 fromX = fromY = -1;
\r
5566 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5567 fromX = fromY = -1;
\r
5571 barbaric = 0; appData.language = "";
\r
5572 TranslateMenus(0);
\r
5573 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5574 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5575 lastChecked = wmId;
\r
5579 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5580 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5582 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5583 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5584 TranslateMenus(0);
\r
5585 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5586 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5587 lastChecked = wmId;
\r
5590 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5596 case CLOCK_TIMER_ID:
\r
5597 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5598 clockTimerEvent = 0;
\r
5599 DecrementClocks(); /* call into back end */
\r
5601 case LOAD_GAME_TIMER_ID:
\r
5602 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5603 loadGameTimerEvent = 0;
\r
5604 AutoPlayGameLoop(); /* call into back end */
\r
5606 case ANALYSIS_TIMER_ID:
\r
5607 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5608 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5609 AnalysisPeriodicEvent(0);
\r
5611 KillTimer(hwnd, analysisTimerEvent);
\r
5612 analysisTimerEvent = 0;
\r
5615 case DELAYED_TIMER_ID:
\r
5616 KillTimer(hwnd, delayedTimerEvent);
\r
5617 delayedTimerEvent = 0;
\r
5618 delayedTimerCallback();
\r
5623 case WM_USER_Input:
\r
5624 InputEvent(hwnd, message, wParam, lParam);
\r
5627 /* [AS] Also move "attached" child windows */
\r
5628 case WM_WINDOWPOSCHANGING:
\r
5630 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5631 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5633 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5634 /* Window is moving */
\r
5637 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5638 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5639 rcMain.right = wpMain.x + wpMain.width;
\r
5640 rcMain.top = wpMain.y;
\r
5641 rcMain.bottom = wpMain.y + wpMain.height;
\r
5643 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5644 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5645 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5646 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5647 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5648 wpMain.x = lpwp->x;
\r
5649 wpMain.y = lpwp->y;
\r
5654 /* [AS] Snapping */
\r
5655 case WM_ENTERSIZEMOVE:
\r
5656 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5657 if (hwnd == hwndMain) {
\r
5658 doingSizing = TRUE;
\r
5661 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5665 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5666 if (hwnd == hwndMain) {
\r
5667 lastSizing = wParam;
\r
5672 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5673 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5675 case WM_EXITSIZEMOVE:
\r
5676 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5677 if (hwnd == hwndMain) {
\r
5679 doingSizing = FALSE;
\r
5680 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5681 GetClientRect(hwnd, &client);
\r
5682 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5684 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5686 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5689 case WM_DESTROY: /* message: window being destroyed */
\r
5690 PostQuitMessage(0);
\r
5694 if (hwnd == hwndMain) {
\r
5699 default: /* Passes it on if unprocessed */
\r
5700 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5705 /*---------------------------------------------------------------------------*\
\r
5707 * Misc utility routines
\r
5709 \*---------------------------------------------------------------------------*/
\r
5712 * Decent random number generator, at least not as bad as Windows
\r
5713 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5715 unsigned int randstate;
\r
5720 randstate = randstate * 1664525 + 1013904223;
\r
5721 return (int) randstate & 0x7fffffff;
\r
5725 mysrandom(unsigned int seed)
\r
5732 * returns TRUE if user selects a different color, FALSE otherwise
\r
5736 ChangeColor(HWND hwnd, COLORREF *which)
\r
5738 static BOOL firstTime = TRUE;
\r
5739 static DWORD customColors[16];
\r
5741 COLORREF newcolor;
\r
5746 /* Make initial colors in use available as custom colors */
\r
5747 /* Should we put the compiled-in defaults here instead? */
\r
5749 customColors[i++] = lightSquareColor & 0xffffff;
\r
5750 customColors[i++] = darkSquareColor & 0xffffff;
\r
5751 customColors[i++] = whitePieceColor & 0xffffff;
\r
5752 customColors[i++] = blackPieceColor & 0xffffff;
\r
5753 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5754 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5756 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5757 customColors[i++] = textAttribs[ccl].color;
\r
5759 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5760 firstTime = FALSE;
\r
5763 cc.lStructSize = sizeof(cc);
\r
5764 cc.hwndOwner = hwnd;
\r
5765 cc.hInstance = NULL;
\r
5766 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5767 cc.lpCustColors = (LPDWORD) customColors;
\r
5768 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5770 if (!ChooseColor(&cc)) return FALSE;
\r
5772 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5773 if (newcolor == *which) return FALSE;
\r
5774 *which = newcolor;
\r
5778 InitDrawingColors();
\r
5779 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5784 MyLoadSound(MySound *ms)
\r
5790 if (ms->data && ms->flag) free(ms->data);
\r
5793 switch (ms->name[0]) {
\r
5799 /* System sound from Control Panel. Don't preload here. */
\r
5803 if (ms->name[1] == NULLCHAR) {
\r
5804 /* "!" alone = silence */
\r
5807 /* Builtin wave resource. Error if not found. */
\r
5808 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5809 if (h == NULL) break;
\r
5810 ms->data = (void *)LoadResource(hInst, h);
\r
5811 ms->flag = 0; // not maloced, so cannot be freed!
\r
5812 if (h == NULL) break;
\r
5817 /* .wav file. Error if not found. */
\r
5818 f = fopen(ms->name, "rb");
\r
5819 if (f == NULL) break;
\r
5820 if (fstat(fileno(f), &st) < 0) break;
\r
5821 ms->data = malloc(st.st_size);
\r
5823 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5829 char buf[MSG_SIZ];
\r
5830 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5831 DisplayError(buf, GetLastError());
\r
5837 MyPlaySound(MySound *ms)
\r
5839 BOOLEAN ok = FALSE;
\r
5841 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5842 switch (ms->name[0]) {
\r
5844 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5849 /* System sound from Control Panel (deprecated feature).
\r
5850 "$" alone or an unset sound name gets default beep (still in use). */
\r
5851 if (ms->name[1]) {
\r
5852 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5854 if (!ok) ok = MessageBeep(MB_OK);
\r
5857 /* Builtin wave resource, or "!" alone for silence */
\r
5858 if (ms->name[1]) {
\r
5859 if (ms->data == NULL) return FALSE;
\r
5860 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5866 /* .wav file. Error if not found. */
\r
5867 if (ms->data == NULL) return FALSE;
\r
5868 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5871 /* Don't print an error: this can happen innocently if the sound driver
\r
5872 is busy; for instance, if another instance of WinBoard is playing
\r
5873 a sound at about the same time. */
\r
5879 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5882 OPENFILENAME *ofn;
\r
5883 static UINT *number; /* gross that this is static */
\r
5885 switch (message) {
\r
5886 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5887 /* Center the dialog over the application window */
\r
5888 ofn = (OPENFILENAME *) lParam;
\r
5889 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5890 number = (UINT *) ofn->lCustData;
\r
5891 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5895 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5896 Translate(hDlg, 1536);
\r
5897 return FALSE; /* Allow for further processing */
\r
5900 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5901 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5903 return FALSE; /* Allow for further processing */
\r
5909 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5911 static UINT *number;
\r
5912 OPENFILENAME *ofname;
\r
5915 case WM_INITDIALOG:
\r
5916 Translate(hdlg, DLG_IndexNumber);
\r
5917 ofname = (OPENFILENAME *)lParam;
\r
5918 number = (UINT *)(ofname->lCustData);
\r
5921 ofnot = (OFNOTIFY *)lParam;
\r
5922 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5923 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5932 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5933 char *nameFilt, char *dlgTitle, UINT *number,
\r
5934 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5936 OPENFILENAME openFileName;
\r
5937 char buf1[MSG_SIZ];
\r
5940 if (fileName == NULL) fileName = buf1;
\r
5941 if (defName == NULL) {
\r
5942 safeStrCpy(fileName, "*.", 3 );
\r
5943 strcat(fileName, defExt);
\r
5945 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5947 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
5948 if (number) *number = 0;
\r
5950 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5951 openFileName.hwndOwner = hwnd;
\r
5952 openFileName.hInstance = (HANDLE) hInst;
\r
5953 openFileName.lpstrFilter = nameFilt;
\r
5954 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5955 openFileName.nMaxCustFilter = 0L;
\r
5956 openFileName.nFilterIndex = 1L;
\r
5957 openFileName.lpstrFile = fileName;
\r
5958 openFileName.nMaxFile = MSG_SIZ;
\r
5959 openFileName.lpstrFileTitle = fileTitle;
\r
5960 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5961 openFileName.lpstrInitialDir = NULL;
\r
5962 openFileName.lpstrTitle = dlgTitle;
\r
5963 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5964 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
5965 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5966 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5967 openFileName.nFileOffset = 0;
\r
5968 openFileName.nFileExtension = 0;
\r
5969 openFileName.lpstrDefExt = defExt;
\r
5970 openFileName.lCustData = (LONG) number;
\r
5971 openFileName.lpfnHook = oldDialog ?
\r
5972 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5973 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5975 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
5976 GetOpenFileName(&openFileName)) {
\r
5977 /* open the file */
\r
5978 f = fopen(openFileName.lpstrFile, write);
\r
5980 MessageBox(hwnd, _("File open failed"), NULL,
\r
5981 MB_OK|MB_ICONEXCLAMATION);
\r
5985 int err = CommDlgExtendedError();
\r
5986 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
5995 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5997 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6000 * Get the first pop-up menu in the menu template. This is the
\r
6001 * menu that TrackPopupMenu displays.
\r
6003 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6004 TranslateOneMenu(10, hmenuTrackPopup);
\r
6006 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6009 * TrackPopup uses screen coordinates, so convert the
\r
6010 * coordinates of the mouse click to screen coordinates.
\r
6012 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6014 /* Draw and track the floating pop-up menu. */
\r
6015 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6016 pt.x, pt.y, 0, hwnd, NULL);
\r
6018 /* Destroy the menu.*/
\r
6019 DestroyMenu(hmenu);
\r
6024 int sizeX, sizeY, newSizeX, newSizeY;
\r
6026 } ResizeEditPlusButtonsClosure;
\r
6029 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6031 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6035 if (hChild == cl->hText) return TRUE;
\r
6036 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6037 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6038 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6039 ScreenToClient(cl->hDlg, &pt);
\r
6040 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6041 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6045 /* Resize a dialog that has a (rich) edit field filling most of
\r
6046 the top, with a row of buttons below */
\r
6048 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6051 int newTextHeight, newTextWidth;
\r
6052 ResizeEditPlusButtonsClosure cl;
\r
6054 /*if (IsIconic(hDlg)) return;*/
\r
6055 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6057 cl.hdwp = BeginDeferWindowPos(8);
\r
6059 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6060 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6061 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6062 if (newTextHeight < 0) {
\r
6063 newSizeY += -newTextHeight;
\r
6064 newTextHeight = 0;
\r
6066 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6067 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6073 cl.newSizeX = newSizeX;
\r
6074 cl.newSizeY = newSizeY;
\r
6075 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6077 EndDeferWindowPos(cl.hdwp);
\r
6080 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6082 RECT rChild, rParent;
\r
6083 int wChild, hChild, wParent, hParent;
\r
6084 int wScreen, hScreen, xNew, yNew;
\r
6087 /* Get the Height and Width of the child window */
\r
6088 GetWindowRect (hwndChild, &rChild);
\r
6089 wChild = rChild.right - rChild.left;
\r
6090 hChild = rChild.bottom - rChild.top;
\r
6092 /* Get the Height and Width of the parent window */
\r
6093 GetWindowRect (hwndParent, &rParent);
\r
6094 wParent = rParent.right - rParent.left;
\r
6095 hParent = rParent.bottom - rParent.top;
\r
6097 /* Get the display limits */
\r
6098 hdc = GetDC (hwndChild);
\r
6099 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6100 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6101 ReleaseDC(hwndChild, hdc);
\r
6103 /* Calculate new X position, then adjust for screen */
\r
6104 xNew = rParent.left + ((wParent - wChild) /2);
\r
6107 } else if ((xNew+wChild) > wScreen) {
\r
6108 xNew = wScreen - wChild;
\r
6111 /* Calculate new Y position, then adjust for screen */
\r
6113 yNew = rParent.top + ((hParent - hChild) /2);
\r
6116 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6121 } else if ((yNew+hChild) > hScreen) {
\r
6122 yNew = hScreen - hChild;
\r
6125 /* Set it, and return */
\r
6126 return SetWindowPos (hwndChild, NULL,
\r
6127 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6130 /* Center one window over another */
\r
6131 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6133 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6136 /*---------------------------------------------------------------------------*\
\r
6138 * Startup Dialog functions
\r
6140 \*---------------------------------------------------------------------------*/
\r
6142 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6144 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6146 while (*cd != NULL) {
\r
6147 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6153 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6155 char buf1[MAX_ARG_LEN];
\r
6158 if (str[0] == '@') {
\r
6159 FILE* f = fopen(str + 1, "r");
\r
6161 DisplayFatalError(str + 1, errno, 2);
\r
6164 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6166 buf1[len] = NULLCHAR;
\r
6170 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6173 char buf[MSG_SIZ];
\r
6174 char *end = strchr(str, '\n');
\r
6175 if (end == NULL) return;
\r
6176 memcpy(buf, str, end - str);
\r
6177 buf[end - str] = NULLCHAR;
\r
6178 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6184 SetStartupDialogEnables(HWND hDlg)
\r
6186 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6187 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6188 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6189 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6190 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6191 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6192 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6193 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6194 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6195 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6196 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6197 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6198 IsDlgButtonChecked(hDlg, OPT_View));
\r
6202 QuoteForFilename(char *filename)
\r
6204 int dquote, space;
\r
6205 dquote = strchr(filename, '"') != NULL;
\r
6206 space = strchr(filename, ' ') != NULL;
\r
6207 if (dquote || space) {
\r
6219 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6221 char buf[MSG_SIZ];
\r
6224 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6225 q = QuoteForFilename(nthcp);
\r
6226 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6227 if (*nthdir != NULLCHAR) {
\r
6228 q = QuoteForFilename(nthdir);
\r
6229 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6231 if (*nthcp == NULLCHAR) {
\r
6232 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6233 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6234 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6235 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6240 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6242 char buf[MSG_SIZ];
\r
6246 switch (message) {
\r
6247 case WM_INITDIALOG:
\r
6248 /* Center the dialog */
\r
6249 CenterWindow (hDlg, GetDesktopWindow());
\r
6250 Translate(hDlg, DLG_Startup);
\r
6251 /* Initialize the dialog items */
\r
6252 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6253 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6254 firstChessProgramNames);
\r
6255 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6256 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6257 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6258 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6259 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6260 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6261 if (*appData.icsHelper != NULLCHAR) {
\r
6262 char *q = QuoteForFilename(appData.icsHelper);
\r
6263 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6265 if (*appData.icsHost == NULLCHAR) {
\r
6266 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6267 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6268 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6269 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6270 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6273 if (appData.icsActive) {
\r
6274 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6276 else if (appData.noChessProgram) {
\r
6277 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6280 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6283 SetStartupDialogEnables(hDlg);
\r
6287 switch (LOWORD(wParam)) {
\r
6289 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6290 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6291 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6293 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6294 ParseArgs(StringGet, &p);
\r
6295 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6296 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6298 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6299 ParseArgs(StringGet, &p);
\r
6300 SwapEngines(singleList); // ... and then make it 'second'
\r
6302 appData.noChessProgram = FALSE;
\r
6303 appData.icsActive = FALSE;
\r
6304 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6305 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6306 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6308 ParseArgs(StringGet, &p);
\r
6309 if (appData.zippyPlay) {
\r
6310 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6311 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6313 ParseArgs(StringGet, &p);
\r
6315 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6316 appData.noChessProgram = TRUE;
\r
6317 appData.icsActive = FALSE;
\r
6319 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6320 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6323 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6324 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6326 ParseArgs(StringGet, &p);
\r
6328 EndDialog(hDlg, TRUE);
\r
6335 case IDM_HELPCONTENTS:
\r
6336 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6337 MessageBox (GetFocus(),
\r
6338 _("Unable to activate help"),
\r
6339 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6344 SetStartupDialogEnables(hDlg);
\r
6352 /*---------------------------------------------------------------------------*\
\r
6354 * About box dialog functions
\r
6356 \*---------------------------------------------------------------------------*/
\r
6358 /* Process messages for "About" dialog box */
\r
6360 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6362 switch (message) {
\r
6363 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6364 /* Center the dialog over the application window */
\r
6365 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6366 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6367 Translate(hDlg, ABOUTBOX);
\r
6371 case WM_COMMAND: /* message: received a command */
\r
6372 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6373 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6374 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6382 /*---------------------------------------------------------------------------*\
\r
6384 * Comment Dialog functions
\r
6386 \*---------------------------------------------------------------------------*/
\r
6389 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6391 static HANDLE hwndText = NULL;
\r
6392 int len, newSizeX, newSizeY, flags;
\r
6393 static int sizeX, sizeY;
\r
6398 switch (message) {
\r
6399 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6400 /* Initialize the dialog items */
\r
6401 Translate(hDlg, DLG_EditComment);
\r
6402 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6403 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6404 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6405 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6406 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6407 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6408 SetWindowText(hDlg, commentTitle);
\r
6409 if (editComment) {
\r
6410 SetFocus(hwndText);
\r
6412 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6414 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6415 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6416 MAKELPARAM(FALSE, 0));
\r
6417 /* Size and position the dialog */
\r
6418 if (!commentDialog) {
\r
6419 commentDialog = hDlg;
\r
6420 flags = SWP_NOZORDER;
\r
6421 GetClientRect(hDlg, &rect);
\r
6422 sizeX = rect.right;
\r
6423 sizeY = rect.bottom;
\r
6424 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6425 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6426 WINDOWPLACEMENT wp;
\r
6427 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6428 wp.length = sizeof(WINDOWPLACEMENT);
\r
6430 wp.showCmd = SW_SHOW;
\r
6431 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6432 wp.rcNormalPosition.left = wpComment.x;
\r
6433 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6434 wp.rcNormalPosition.top = wpComment.y;
\r
6435 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6436 SetWindowPlacement(hDlg, &wp);
\r
6438 GetClientRect(hDlg, &rect);
\r
6439 newSizeX = rect.right;
\r
6440 newSizeY = rect.bottom;
\r
6441 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6442 newSizeX, newSizeY);
\r
6447 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6450 case WM_COMMAND: /* message: received a command */
\r
6451 switch (LOWORD(wParam)) {
\r
6453 if (editComment) {
\r
6455 /* Read changed options from the dialog box */
\r
6456 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6457 len = GetWindowTextLength(hwndText);
\r
6458 str = (char *) malloc(len + 1);
\r
6459 GetWindowText(hwndText, str, len + 1);
\r
6468 ReplaceComment(commentIndex, str);
\r
6475 case OPT_CancelComment:
\r
6479 case OPT_ClearComment:
\r
6480 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6483 case OPT_EditComment:
\r
6484 EditCommentEvent();
\r
6492 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6493 if( wParam == OPT_CommentText ) {
\r
6494 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6496 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6497 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6501 pt.x = LOWORD( lpMF->lParam );
\r
6502 pt.y = HIWORD( lpMF->lParam );
\r
6504 if(lpMF->msg == WM_CHAR) {
\r
6506 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6507 index = sel.cpMin;
\r
6509 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6511 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6512 len = GetWindowTextLength(hwndText);
\r
6513 str = (char *) malloc(len + 1);
\r
6514 GetWindowText(hwndText, str, len + 1);
\r
6515 ReplaceComment(commentIndex, str);
\r
6516 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6517 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6520 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6521 lpMF->msg = WM_USER;
\r
6529 newSizeX = LOWORD(lParam);
\r
6530 newSizeY = HIWORD(lParam);
\r
6531 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6536 case WM_GETMINMAXINFO:
\r
6537 /* Prevent resizing window too small */
\r
6538 mmi = (MINMAXINFO *) lParam;
\r
6539 mmi->ptMinTrackSize.x = 100;
\r
6540 mmi->ptMinTrackSize.y = 100;
\r
6547 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6552 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6554 if (str == NULL) str = "";
\r
6555 p = (char *) malloc(2 * strlen(str) + 2);
\r
6558 if (*str == '\n') *q++ = '\r';
\r
6562 if (commentText != NULL) free(commentText);
\r
6564 commentIndex = index;
\r
6565 commentTitle = title;
\r
6567 editComment = edit;
\r
6569 if (commentDialog) {
\r
6570 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6571 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6573 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6574 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6575 hwndMain, (DLGPROC)lpProc);
\r
6576 FreeProcInstance(lpProc);
\r
6582 /*---------------------------------------------------------------------------*\
\r
6584 * Type-in move dialog functions
\r
6586 \*---------------------------------------------------------------------------*/
\r
6589 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6591 char move[MSG_SIZ];
\r
6594 switch (message) {
\r
6595 case WM_INITDIALOG:
\r
6596 move[0] = (char) lParam;
\r
6597 move[1] = NULLCHAR;
\r
6598 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6599 Translate(hDlg, DLG_TypeInMove);
\r
6600 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6601 SetWindowText(hInput, move);
\r
6603 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6607 switch (LOWORD(wParam)) {
\r
6610 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6611 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6612 TypeInDoneEvent(move);
\r
6613 EndDialog(hDlg, TRUE);
\r
6616 EndDialog(hDlg, FALSE);
\r
6627 PopUpMoveDialog(char firstchar)
\r
6631 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6632 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6633 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6634 FreeProcInstance(lpProc);
\r
6637 /*---------------------------------------------------------------------------*\
\r
6639 * Type-in name dialog functions
\r
6641 \*---------------------------------------------------------------------------*/
\r
6644 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6646 char move[MSG_SIZ];
\r
6649 switch (message) {
\r
6650 case WM_INITDIALOG:
\r
6651 move[0] = (char) lParam;
\r
6652 move[1] = NULLCHAR;
\r
6653 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6654 Translate(hDlg, DLG_TypeInName);
\r
6655 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6656 SetWindowText(hInput, move);
\r
6658 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6662 switch (LOWORD(wParam)) {
\r
6664 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6665 appData.userName = strdup(move);
\r
6668 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6669 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6670 DisplayTitle(move);
\r
6674 EndDialog(hDlg, TRUE);
\r
6677 EndDialog(hDlg, FALSE);
\r
6688 PopUpNameDialog(char firstchar)
\r
6692 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6693 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6694 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6695 FreeProcInstance(lpProc);
\r
6698 /*---------------------------------------------------------------------------*\
\r
6702 \*---------------------------------------------------------------------------*/
\r
6704 /* Nonmodal error box */
\r
6705 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6706 WPARAM wParam, LPARAM lParam);
\r
6709 ErrorPopUp(char *title, char *content)
\r
6713 BOOLEAN modal = hwndMain == NULL;
\r
6731 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6732 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6735 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6737 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6738 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6739 hwndMain, (DLGPROC)lpProc);
\r
6740 FreeProcInstance(lpProc);
\r
6747 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6748 if (errorDialog == NULL) return;
\r
6749 DestroyWindow(errorDialog);
\r
6750 errorDialog = NULL;
\r
6751 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6755 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6760 switch (message) {
\r
6761 case WM_INITDIALOG:
\r
6762 GetWindowRect(hDlg, &rChild);
\r
6765 SetWindowPos(hDlg, NULL, rChild.left,
\r
6766 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6767 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6771 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6772 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6773 and it doesn't work when you resize the dialog.
\r
6774 For now, just give it a default position.
\r
6776 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6777 Translate(hDlg, DLG_Error);
\r
6779 errorDialog = hDlg;
\r
6780 SetWindowText(hDlg, errorTitle);
\r
6781 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6782 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6786 switch (LOWORD(wParam)) {
\r
6789 if (errorDialog == hDlg) errorDialog = NULL;
\r
6790 DestroyWindow(hDlg);
\r
6802 HWND gothicDialog = NULL;
\r
6805 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6809 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6811 switch (message) {
\r
6812 case WM_INITDIALOG:
\r
6813 GetWindowRect(hDlg, &rChild);
\r
6815 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6819 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6820 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6821 and it doesn't work when you resize the dialog.
\r
6822 For now, just give it a default position.
\r
6824 gothicDialog = hDlg;
\r
6825 SetWindowText(hDlg, errorTitle);
\r
6826 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6827 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6831 switch (LOWORD(wParam)) {
\r
6834 if (errorDialog == hDlg) errorDialog = NULL;
\r
6835 DestroyWindow(hDlg);
\r
6847 GothicPopUp(char *title, VariantClass variant)
\r
6850 static char *lastTitle;
\r
6852 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6853 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6855 if(lastTitle != title && gothicDialog != NULL) {
\r
6856 DestroyWindow(gothicDialog);
\r
6857 gothicDialog = NULL;
\r
6859 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6860 title = lastTitle;
\r
6861 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6862 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6863 hwndMain, (DLGPROC)lpProc);
\r
6864 FreeProcInstance(lpProc);
\r
6869 /*---------------------------------------------------------------------------*\
\r
6871 * Ics Interaction console functions
\r
6873 \*---------------------------------------------------------------------------*/
\r
6875 #define HISTORY_SIZE 64
\r
6876 static char *history[HISTORY_SIZE];
\r
6877 int histIn = 0, histP = 0;
\r
6881 SaveInHistory(char *cmd)
\r
6883 if (history[histIn] != NULL) {
\r
6884 free(history[histIn]);
\r
6885 history[histIn] = NULL;
\r
6887 if (*cmd == NULLCHAR) return;
\r
6888 history[histIn] = StrSave(cmd);
\r
6889 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6890 if (history[histIn] != NULL) {
\r
6891 free(history[histIn]);
\r
6893 history[histIn] = NULL;
\r
6899 PrevInHistory(char *cmd)
\r
6902 if (histP == histIn) {
\r
6903 if (history[histIn] != NULL) free(history[histIn]);
\r
6904 history[histIn] = StrSave(cmd);
\r
6906 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6907 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6909 return history[histP];
\r
6915 if (histP == histIn) return NULL;
\r
6916 histP = (histP + 1) % HISTORY_SIZE;
\r
6917 return history[histP];
\r
6921 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6925 hmenu = LoadMenu(hInst, "TextMenu");
\r
6926 h = GetSubMenu(hmenu, 0);
\r
6928 if (strcmp(e->item, "-") == 0) {
\r
6929 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6930 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6931 int flags = MF_STRING, j = 0;
\r
6932 if (e->item[0] == '|') {
\r
6933 flags |= MF_MENUBARBREAK;
\r
6936 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6937 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6945 WNDPROC consoleTextWindowProc;
\r
6948 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6950 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6951 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6955 SetWindowText(hInput, command);
\r
6957 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6959 sel.cpMin = 999999;
\r
6960 sel.cpMax = 999999;
\r
6961 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6966 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6967 if (sel.cpMin == sel.cpMax) {
\r
6968 /* Expand to surrounding word */
\r
6971 tr.chrg.cpMax = sel.cpMin;
\r
6972 tr.chrg.cpMin = --sel.cpMin;
\r
6973 if (sel.cpMin < 0) break;
\r
6974 tr.lpstrText = name;
\r
6975 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6976 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6980 tr.chrg.cpMin = sel.cpMax;
\r
6981 tr.chrg.cpMax = ++sel.cpMax;
\r
6982 tr.lpstrText = name;
\r
6983 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6984 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6987 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6988 MessageBeep(MB_ICONEXCLAMATION);
\r
6992 tr.lpstrText = name;
\r
6993 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6995 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6996 MessageBeep(MB_ICONEXCLAMATION);
\r
6999 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7002 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7003 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7004 SetWindowText(hInput, buf);
\r
7005 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7007 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7008 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7009 SetWindowText(hInput, buf);
\r
7010 sel.cpMin = 999999;
\r
7011 sel.cpMax = 999999;
\r
7012 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7018 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7023 switch (message) {
\r
7025 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7026 if(wParam=='R') return 0;
\r
7029 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7032 sel.cpMin = 999999;
\r
7033 sel.cpMax = 999999;
\r
7034 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7035 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7040 if(wParam != '\022') {
\r
7041 if (wParam == '\t') {
\r
7042 if (GetKeyState(VK_SHIFT) < 0) {
\r
7044 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7045 if (buttonDesc[0].hwnd) {
\r
7046 SetFocus(buttonDesc[0].hwnd);
\r
7048 SetFocus(hwndMain);
\r
7052 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7055 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7056 JAWS_DELETE( SetFocus(hInput); )
\r
7057 SendMessage(hInput, message, wParam, lParam);
\r
7060 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7062 case WM_RBUTTONDOWN:
\r
7063 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7064 /* Move selection here if it was empty */
\r
7066 pt.x = LOWORD(lParam);
\r
7067 pt.y = HIWORD(lParam);
\r
7068 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7069 if (sel.cpMin == sel.cpMax) {
\r
7070 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7071 sel.cpMax = sel.cpMin;
\r
7072 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7074 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7075 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7077 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7078 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7079 if (sel.cpMin == sel.cpMax) {
\r
7080 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7081 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7083 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7084 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7086 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7087 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7088 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7089 MenuPopup(hwnd, pt, hmenu, -1);
\r
7093 case WM_RBUTTONUP:
\r
7094 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7095 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7096 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7100 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7102 return SendMessage(hInput, message, wParam, lParam);
\r
7103 case WM_MBUTTONDOWN:
\r
7104 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7106 switch (LOWORD(wParam)) {
\r
7107 case IDM_QuickPaste:
\r
7109 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7110 if (sel.cpMin == sel.cpMax) {
\r
7111 MessageBeep(MB_ICONEXCLAMATION);
\r
7114 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7115 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7116 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7121 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7124 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7127 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7131 int i = LOWORD(wParam) - IDM_CommandX;
\r
7132 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7133 icsTextMenuEntry[i].command != NULL) {
\r
7134 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7135 icsTextMenuEntry[i].getname,
\r
7136 icsTextMenuEntry[i].immediate);
\r
7144 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7147 WNDPROC consoleInputWindowProc;
\r
7150 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7152 char buf[MSG_SIZ];
\r
7154 static BOOL sendNextChar = FALSE;
\r
7155 static BOOL quoteNextChar = FALSE;
\r
7156 InputSource *is = consoleInputSource;
\r
7160 switch (message) {
\r
7162 if (!appData.localLineEditing || sendNextChar) {
\r
7163 is->buf[0] = (CHAR) wParam;
\r
7165 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7166 sendNextChar = FALSE;
\r
7169 if (quoteNextChar) {
\r
7170 buf[0] = (char) wParam;
\r
7171 buf[1] = NULLCHAR;
\r
7172 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7173 quoteNextChar = FALSE;
\r
7177 case '\r': /* Enter key */
\r
7178 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7179 if (consoleEcho) SaveInHistory(is->buf);
\r
7180 is->buf[is->count++] = '\n';
\r
7181 is->buf[is->count] = NULLCHAR;
\r
7182 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7183 if (consoleEcho) {
\r
7184 ConsoleOutput(is->buf, is->count, TRUE);
\r
7185 } else if (appData.localLineEditing) {
\r
7186 ConsoleOutput("\n", 1, TRUE);
\r
7189 case '\033': /* Escape key */
\r
7190 SetWindowText(hwnd, "");
\r
7191 cf.cbSize = sizeof(CHARFORMAT);
\r
7192 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7193 if (consoleEcho) {
\r
7194 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7196 cf.crTextColor = COLOR_ECHOOFF;
\r
7198 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7199 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7201 case '\t': /* Tab key */
\r
7202 if (GetKeyState(VK_SHIFT) < 0) {
\r
7204 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7207 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7208 if (buttonDesc[0].hwnd) {
\r
7209 SetFocus(buttonDesc[0].hwnd);
\r
7211 SetFocus(hwndMain);
\r
7215 case '\023': /* Ctrl+S */
\r
7216 sendNextChar = TRUE;
\r
7218 case '\021': /* Ctrl+Q */
\r
7219 quoteNextChar = TRUE;
\r
7229 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7230 p = PrevInHistory(buf);
\r
7232 SetWindowText(hwnd, p);
\r
7233 sel.cpMin = 999999;
\r
7234 sel.cpMax = 999999;
\r
7235 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7240 p = NextInHistory();
\r
7242 SetWindowText(hwnd, p);
\r
7243 sel.cpMin = 999999;
\r
7244 sel.cpMax = 999999;
\r
7245 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7251 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7255 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7259 case WM_MBUTTONDOWN:
\r
7260 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7261 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7263 case WM_RBUTTONUP:
\r
7264 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7265 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7266 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7270 hmenu = LoadMenu(hInst, "InputMenu");
\r
7271 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7272 if (sel.cpMin == sel.cpMax) {
\r
7273 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7274 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7276 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7277 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7279 pt.x = LOWORD(lParam);
\r
7280 pt.y = HIWORD(lParam);
\r
7281 MenuPopup(hwnd, pt, hmenu, -1);
\r
7285 switch (LOWORD(wParam)) {
\r
7287 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7289 case IDM_SelectAll:
\r
7291 sel.cpMax = -1; /*999999?*/
\r
7292 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7295 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7298 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7301 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7306 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7309 #define CO_MAX 100000
\r
7310 #define CO_TRIM 1000
\r
7313 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7315 static SnapData sd;
\r
7316 HWND hText, hInput;
\r
7318 static int sizeX, sizeY;
\r
7319 int newSizeX, newSizeY;
\r
7323 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7324 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7326 switch (message) {
\r
7328 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7330 ENLINK *pLink = (ENLINK*)lParam;
\r
7331 if (pLink->msg == WM_LBUTTONUP)
\r
7335 tr.chrg = pLink->chrg;
\r
7336 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7337 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7338 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7339 free(tr.lpstrText);
\r
7343 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7344 hwndConsole = hDlg;
\r
7346 consoleTextWindowProc = (WNDPROC)
\r
7347 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7348 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7349 consoleInputWindowProc = (WNDPROC)
\r
7350 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7351 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7352 Colorize(ColorNormal, TRUE);
\r
7353 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7354 ChangedConsoleFont();
\r
7355 GetClientRect(hDlg, &rect);
\r
7356 sizeX = rect.right;
\r
7357 sizeY = rect.bottom;
\r
7358 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7359 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7360 WINDOWPLACEMENT wp;
\r
7361 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7362 wp.length = sizeof(WINDOWPLACEMENT);
\r
7364 wp.showCmd = SW_SHOW;
\r
7365 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7366 wp.rcNormalPosition.left = wpConsole.x;
\r
7367 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7368 wp.rcNormalPosition.top = wpConsole.y;
\r
7369 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7370 SetWindowPlacement(hDlg, &wp);
\r
7373 // [HGM] Chessknight's change 2004-07-13
\r
7374 else { /* Determine Defaults */
\r
7375 WINDOWPLACEMENT wp;
\r
7376 wpConsole.x = wpMain.width + 1;
\r
7377 wpConsole.y = wpMain.y;
\r
7378 wpConsole.width = screenWidth - wpMain.width;
\r
7379 wpConsole.height = wpMain.height;
\r
7380 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7381 wp.length = sizeof(WINDOWPLACEMENT);
\r
7383 wp.showCmd = SW_SHOW;
\r
7384 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7385 wp.rcNormalPosition.left = wpConsole.x;
\r
7386 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7387 wp.rcNormalPosition.top = wpConsole.y;
\r
7388 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7389 SetWindowPlacement(hDlg, &wp);
\r
7392 // Allow hText to highlight URLs and send notifications on them
\r
7393 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7394 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7395 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7396 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7410 if (IsIconic(hDlg)) break;
\r
7411 newSizeX = LOWORD(lParam);
\r
7412 newSizeY = HIWORD(lParam);
\r
7413 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7414 RECT rectText, rectInput;
\r
7416 int newTextHeight, newTextWidth;
\r
7417 GetWindowRect(hText, &rectText);
\r
7418 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7419 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7420 if (newTextHeight < 0) {
\r
7421 newSizeY += -newTextHeight;
\r
7422 newTextHeight = 0;
\r
7424 SetWindowPos(hText, NULL, 0, 0,
\r
7425 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7426 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7427 pt.x = rectInput.left;
\r
7428 pt.y = rectInput.top + newSizeY - sizeY;
\r
7429 ScreenToClient(hDlg, &pt);
\r
7430 SetWindowPos(hInput, NULL,
\r
7431 pt.x, pt.y, /* needs client coords */
\r
7432 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7433 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7439 case WM_GETMINMAXINFO:
\r
7440 /* Prevent resizing window too small */
\r
7441 mmi = (MINMAXINFO *) lParam;
\r
7442 mmi->ptMinTrackSize.x = 100;
\r
7443 mmi->ptMinTrackSize.y = 100;
\r
7446 /* [AS] Snapping */
\r
7447 case WM_ENTERSIZEMOVE:
\r
7448 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7451 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7454 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7456 case WM_EXITSIZEMOVE:
\r
7457 UpdateICSWidth(hText);
\r
7458 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7461 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7469 if (hwndConsole) return;
\r
7470 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7471 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7476 ConsoleOutput(char* data, int length, int forceVisible)
\r
7481 char buf[CO_MAX+1];
\r
7484 static int delayLF = 0;
\r
7485 CHARRANGE savesel, sel;
\r
7487 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7495 while (length--) {
\r
7503 } else if (*p == '\007') {
\r
7504 MyPlaySound(&sounds[(int)SoundBell]);
\r
7511 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7512 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7513 /* Save current selection */
\r
7514 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7515 exlen = GetWindowTextLength(hText);
\r
7516 /* Find out whether current end of text is visible */
\r
7517 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7518 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7519 /* Trim existing text if it's too long */
\r
7520 if (exlen + (q - buf) > CO_MAX) {
\r
7521 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7524 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7525 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7527 savesel.cpMin -= trim;
\r
7528 savesel.cpMax -= trim;
\r
7529 if (exlen < 0) exlen = 0;
\r
7530 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7531 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7533 /* Append the new text */
\r
7534 sel.cpMin = exlen;
\r
7535 sel.cpMax = exlen;
\r
7536 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7537 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7538 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7539 if (forceVisible || exlen == 0 ||
\r
7540 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7541 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7542 /* Scroll to make new end of text visible if old end of text
\r
7543 was visible or new text is an echo of user typein */
\r
7544 sel.cpMin = 9999999;
\r
7545 sel.cpMax = 9999999;
\r
7546 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7547 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7548 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7549 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7551 if (savesel.cpMax == exlen || forceVisible) {
\r
7552 /* Move insert point to new end of text if it was at the old
\r
7553 end of text or if the new text is an echo of user typein */
\r
7554 sel.cpMin = 9999999;
\r
7555 sel.cpMax = 9999999;
\r
7556 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7558 /* Restore previous selection */
\r
7559 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7561 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7568 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7572 COLORREF oldFg, oldBg;
\r
7576 if(copyNumber > 1)
\r
7577 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7579 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7580 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7581 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7584 rect.right = x + squareSize;
\r
7586 rect.bottom = y + squareSize;
\r
7589 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7590 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7591 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7592 &rect, str, strlen(str), NULL);
\r
7594 (void) SetTextColor(hdc, oldFg);
\r
7595 (void) SetBkColor(hdc, oldBg);
\r
7596 (void) SelectObject(hdc, oldFont);
\r
7600 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7601 RECT *rect, char *color, char *flagFell)
\r
7605 COLORREF oldFg, oldBg;
\r
7608 if (twoBoards && partnerUp) return;
\r
7609 if (appData.clockMode) {
\r
7611 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7613 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7620 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7621 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7623 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7624 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7626 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7630 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7631 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7632 rect, str, strlen(str), NULL);
\r
7633 if(logoHeight > 0 && appData.clockMode) {
\r
7635 str += strlen(color)+2;
\r
7636 r.top = rect->top + logoHeight/2;
\r
7637 r.left = rect->left;
\r
7638 r.right = rect->right;
\r
7639 r.bottom = rect->bottom;
\r
7640 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7641 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7642 &r, str, strlen(str), NULL);
\r
7644 (void) SetTextColor(hdc, oldFg);
\r
7645 (void) SetBkColor(hdc, oldBg);
\r
7646 (void) SelectObject(hdc, oldFont);
\r
7651 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7657 if( count <= 0 ) {
\r
7658 if (appData.debugMode) {
\r
7659 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7662 return ERROR_INVALID_USER_BUFFER;
\r
7665 ResetEvent(ovl->hEvent);
\r
7666 ovl->Offset = ovl->OffsetHigh = 0;
\r
7667 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7671 err = GetLastError();
\r
7672 if (err == ERROR_IO_PENDING) {
\r
7673 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7677 err = GetLastError();
\r
7684 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7689 ResetEvent(ovl->hEvent);
\r
7690 ovl->Offset = ovl->OffsetHigh = 0;
\r
7691 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7695 err = GetLastError();
\r
7696 if (err == ERROR_IO_PENDING) {
\r
7697 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7701 err = GetLastError();
\r
7708 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7709 void CheckForInputBufferFull( InputSource * is )
\r
7711 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7712 /* Look for end of line */
\r
7713 char * p = is->buf;
\r
7715 while( p < is->next && *p != '\n' ) {
\r
7719 if( p >= is->next ) {
\r
7720 if (appData.debugMode) {
\r
7721 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7724 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7725 is->count = (DWORD) -1;
\r
7726 is->next = is->buf;
\r
7732 InputThread(LPVOID arg)
\r
7737 is = (InputSource *) arg;
\r
7738 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7739 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7740 while (is->hThread != NULL) {
\r
7741 is->error = DoReadFile(is->hFile, is->next,
\r
7742 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7743 &is->count, &ovl);
\r
7744 if (is->error == NO_ERROR) {
\r
7745 is->next += is->count;
\r
7747 if (is->error == ERROR_BROKEN_PIPE) {
\r
7748 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7751 is->count = (DWORD) -1;
\r
7752 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7757 CheckForInputBufferFull( is );
\r
7759 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7761 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7763 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7766 CloseHandle(ovl.hEvent);
\r
7767 CloseHandle(is->hFile);
\r
7769 if (appData.debugMode) {
\r
7770 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7777 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7779 NonOvlInputThread(LPVOID arg)
\r
7786 is = (InputSource *) arg;
\r
7787 while (is->hThread != NULL) {
\r
7788 is->error = ReadFile(is->hFile, is->next,
\r
7789 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7790 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7791 if (is->error == NO_ERROR) {
\r
7792 /* Change CRLF to LF */
\r
7793 if (is->next > is->buf) {
\r
7795 i = is->count + 1;
\r
7803 if (prev == '\r' && *p == '\n') {
\r
7815 if (is->error == ERROR_BROKEN_PIPE) {
\r
7816 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7819 is->count = (DWORD) -1;
\r
7823 CheckForInputBufferFull( is );
\r
7825 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7827 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7829 if (is->count < 0) break; /* Quit on error */
\r
7831 CloseHandle(is->hFile);
\r
7836 SocketInputThread(LPVOID arg)
\r
7840 is = (InputSource *) arg;
\r
7841 while (is->hThread != NULL) {
\r
7842 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7843 if ((int)is->count == SOCKET_ERROR) {
\r
7844 is->count = (DWORD) -1;
\r
7845 is->error = WSAGetLastError();
\r
7847 is->error = NO_ERROR;
\r
7848 is->next += is->count;
\r
7849 if (is->count == 0 && is->second == is) {
\r
7850 /* End of file on stderr; quit with no message */
\r
7854 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7856 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7858 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7864 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7868 is = (InputSource *) lParam;
\r
7869 if (is->lineByLine) {
\r
7870 /* Feed in lines one by one */
\r
7871 char *p = is->buf;
\r
7873 while (q < is->next) {
\r
7874 if (*q++ == '\n') {
\r
7875 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7880 /* Move any partial line to the start of the buffer */
\r
7882 while (p < is->next) {
\r
7887 if (is->error != NO_ERROR || is->count == 0) {
\r
7888 /* Notify backend of the error. Note: If there was a partial
\r
7889 line at the end, it is not flushed through. */
\r
7890 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7893 /* Feed in the whole chunk of input at once */
\r
7894 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7895 is->next = is->buf;
\r
7899 /*---------------------------------------------------------------------------*\
\r
7901 * Menu enables. Used when setting various modes.
\r
7903 \*---------------------------------------------------------------------------*/
\r
7911 GreyRevert(Boolean grey)
\r
7912 { // [HGM] vari: for retracting variations in local mode
\r
7913 HMENU hmenu = GetMenu(hwndMain);
\r
7914 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7915 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7919 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7921 while (enab->item > 0) {
\r
7922 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7927 Enables gnuEnables[] = {
\r
7928 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7929 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7930 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7931 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7932 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7933 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7934 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7935 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7936 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7937 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7938 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7939 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7940 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7942 // Needed to switch from ncp to GNU mode on Engine Load
\r
7943 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7944 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7945 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7946 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7947 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7948 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7949 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7950 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7951 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7952 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
7953 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7954 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7955 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7956 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7960 Enables icsEnables[] = {
\r
7961 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7962 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7963 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7964 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7965 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7966 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
7967 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
7968 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7969 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7970 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7971 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7972 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7977 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7980 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
7985 Enables zippyEnables[] = {
\r
7986 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7994 Enables ncpEnables[] = {
\r
7995 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7996 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7997 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7998 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7999 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8000 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8001 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8002 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8003 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8004 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8005 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8006 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8007 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8020 Enables trainingOnEnables[] = {
\r
8021 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8024 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8025 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8026 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8027 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8028 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8029 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8033 Enables trainingOffEnables[] = {
\r
8034 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8037 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8038 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8039 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8040 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8041 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8042 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8046 /* These modify either ncpEnables or gnuEnables */
\r
8047 Enables cmailEnables[] = {
\r
8048 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8049 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8050 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8051 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8053 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8058 Enables machineThinkingEnables[] = {
\r
8059 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8066 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8072 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8078 Enables userThinkingEnables[] = {
\r
8079 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8080 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8081 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8082 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8083 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8084 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8085 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8086 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8087 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8088 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8089 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8090 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8091 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8092 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8093 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8094 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8098 /*---------------------------------------------------------------------------*\
\r
8100 * Front-end interface functions exported by XBoard.
\r
8101 * Functions appear in same order as prototypes in frontend.h.
\r
8103 \*---------------------------------------------------------------------------*/
\r
8105 CheckMark(UINT item, int state)
\r
8107 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8113 static UINT prevChecked = 0;
\r
8114 static int prevPausing = 0;
\r
8117 if (pausing != prevPausing) {
\r
8118 prevPausing = pausing;
\r
8119 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8120 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8121 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8124 switch (gameMode) {
\r
8125 case BeginningOfGame:
\r
8126 if (appData.icsActive)
\r
8127 nowChecked = IDM_IcsClient;
\r
8128 else if (appData.noChessProgram)
\r
8129 nowChecked = IDM_EditGame;
\r
8131 nowChecked = IDM_MachineBlack;
\r
8133 case MachinePlaysBlack:
\r
8134 nowChecked = IDM_MachineBlack;
\r
8136 case MachinePlaysWhite:
\r
8137 nowChecked = IDM_MachineWhite;
\r
8139 case TwoMachinesPlay:
\r
8140 nowChecked = IDM_TwoMachines;
\r
8143 nowChecked = IDM_AnalysisMode;
\r
8146 nowChecked = IDM_AnalyzeFile;
\r
8149 nowChecked = IDM_EditGame;
\r
8151 case PlayFromGameFile:
\r
8152 nowChecked = IDM_LoadGame;
\r
8154 case EditPosition:
\r
8155 nowChecked = IDM_EditPosition;
\r
8158 nowChecked = IDM_Training;
\r
8160 case IcsPlayingWhite:
\r
8161 case IcsPlayingBlack:
\r
8162 case IcsObserving:
\r
8164 nowChecked = IDM_IcsClient;
\r
8171 CheckMark(prevChecked, MF_UNCHECKED);
\r
8172 CheckMark(nowChecked, MF_CHECKED);
\r
8173 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8175 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8176 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8177 MF_BYCOMMAND|MF_ENABLED);
\r
8179 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8180 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8183 prevChecked = nowChecked;
\r
8185 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8186 if (appData.icsActive) {
\r
8187 if (appData.icsEngineAnalyze) {
\r
8188 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8190 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8193 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8199 HMENU hmenu = GetMenu(hwndMain);
\r
8200 SetMenuEnables(hmenu, icsEnables);
\r
8201 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8202 MF_BYCOMMAND|MF_ENABLED);
\r
8204 if (appData.zippyPlay) {
\r
8205 SetMenuEnables(hmenu, zippyEnables);
\r
8206 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8207 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8208 MF_BYCOMMAND|MF_ENABLED);
\r
8216 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8222 HMENU hmenu = GetMenu(hwndMain);
\r
8223 SetMenuEnables(hmenu, ncpEnables);
\r
8224 DrawMenuBar(hwndMain);
\r
8230 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8234 SetTrainingModeOn()
\r
8237 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8238 for (i = 0; i < N_BUTTONS; i++) {
\r
8239 if (buttonDesc[i].hwnd != NULL)
\r
8240 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8245 VOID SetTrainingModeOff()
\r
8248 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8249 for (i = 0; i < N_BUTTONS; i++) {
\r
8250 if (buttonDesc[i].hwnd != NULL)
\r
8251 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8257 SetUserThinkingEnables()
\r
8259 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8263 SetMachineThinkingEnables()
\r
8265 HMENU hMenu = GetMenu(hwndMain);
\r
8266 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8268 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8270 if (gameMode == MachinePlaysBlack) {
\r
8271 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8272 } else if (gameMode == MachinePlaysWhite) {
\r
8273 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8274 } else if (gameMode == TwoMachinesPlay) {
\r
8275 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8281 DisplayTitle(char *str)
\r
8283 char title[MSG_SIZ], *host;
\r
8284 if (str[0] != NULLCHAR) {
\r
8285 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8286 } else if (appData.icsActive) {
\r
8287 if (appData.icsCommPort[0] != NULLCHAR)
\r
8290 host = appData.icsHost;
\r
8291 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8292 } else if (appData.noChessProgram) {
\r
8293 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8295 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8296 strcat(title, ": ");
\r
8297 strcat(title, first.tidy);
\r
8299 SetWindowText(hwndMain, title);
\r
8304 DisplayMessage(char *str1, char *str2)
\r
8308 int remain = MESSAGE_TEXT_MAX - 1;
\r
8311 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8312 messageText[0] = NULLCHAR;
\r
8314 len = strlen(str1);
\r
8315 if (len > remain) len = remain;
\r
8316 strncpy(messageText, str1, len);
\r
8317 messageText[len] = NULLCHAR;
\r
8320 if (*str2 && remain >= 2) {
\r
8322 strcat(messageText, " ");
\r
8325 len = strlen(str2);
\r
8326 if (len > remain) len = remain;
\r
8327 strncat(messageText, str2, len);
\r
8329 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8330 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8332 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8336 hdc = GetDC(hwndMain);
\r
8337 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8338 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8339 &messageRect, messageText, strlen(messageText), NULL);
\r
8340 (void) SelectObject(hdc, oldFont);
\r
8341 (void) ReleaseDC(hwndMain, hdc);
\r
8345 DisplayError(char *str, int error)
\r
8347 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8351 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8353 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8354 NULL, error, LANG_NEUTRAL,
\r
8355 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8357 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8359 ErrorMap *em = errmap;
\r
8360 while (em->err != 0 && em->err != error) em++;
\r
8361 if (em->err != 0) {
\r
8362 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8364 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8369 ErrorPopUp(_("Error"), buf);
\r
8374 DisplayMoveError(char *str)
\r
8376 fromX = fromY = -1;
\r
8377 ClearHighlights();
\r
8378 DrawPosition(FALSE, NULL);
\r
8379 if (appData.popupMoveErrors) {
\r
8380 ErrorPopUp(_("Error"), str);
\r
8382 DisplayMessage(str, "");
\r
8383 moveErrorMessageUp = TRUE;
\r
8388 DisplayFatalError(char *str, int error, int exitStatus)
\r
8390 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8392 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8395 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8396 NULL, error, LANG_NEUTRAL,
\r
8397 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8399 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8401 ErrorMap *em = errmap;
\r
8402 while (em->err != 0 && em->err != error) em++;
\r
8403 if (em->err != 0) {
\r
8404 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8406 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8411 if (appData.debugMode) {
\r
8412 fprintf(debugFP, "%s: %s\n", label, str);
\r
8414 if (appData.popupExitMessage) {
\r
8415 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8416 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8418 ExitEvent(exitStatus);
\r
8423 DisplayInformation(char *str)
\r
8425 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8430 DisplayNote(char *str)
\r
8432 ErrorPopUp(_("Note"), str);
\r
8437 char *title, *question, *replyPrefix;
\r
8442 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8444 static QuestionParams *qp;
\r
8445 char reply[MSG_SIZ];
\r
8448 switch (message) {
\r
8449 case WM_INITDIALOG:
\r
8450 qp = (QuestionParams *) lParam;
\r
8451 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8452 Translate(hDlg, DLG_Question);
\r
8453 SetWindowText(hDlg, qp->title);
\r
8454 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8455 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8459 switch (LOWORD(wParam)) {
\r
8461 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8462 if (*reply) strcat(reply, " ");
\r
8463 len = strlen(reply);
\r
8464 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8465 strcat(reply, "\n");
\r
8466 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8467 EndDialog(hDlg, TRUE);
\r
8468 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8471 EndDialog(hDlg, FALSE);
\r
8482 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8484 QuestionParams qp;
\r
8488 qp.question = question;
\r
8489 qp.replyPrefix = replyPrefix;
\r
8491 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8492 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8493 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8494 FreeProcInstance(lpProc);
\r
8497 /* [AS] Pick FRC position */
\r
8498 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8500 static int * lpIndexFRC;
\r
8506 case WM_INITDIALOG:
\r
8507 lpIndexFRC = (int *) lParam;
\r
8509 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8510 Translate(hDlg, DLG_NewGameFRC);
\r
8512 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8513 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8514 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8515 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8520 switch( LOWORD(wParam) ) {
\r
8522 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8523 EndDialog( hDlg, 0 );
\r
8524 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8527 EndDialog( hDlg, 1 );
\r
8529 case IDC_NFG_Edit:
\r
8530 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8531 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8533 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8536 case IDC_NFG_Random:
\r
8537 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8538 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8551 int index = appData.defaultFrcPosition;
\r
8552 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8554 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8556 if( result == 0 ) {
\r
8557 appData.defaultFrcPosition = index;
\r
8563 /* [AS] Game list options. Refactored by HGM */
\r
8565 HWND gameListOptionsDialog;
\r
8567 // low-level front-end: clear text edit / list widget
\r
8572 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8575 // low-level front-end: clear text edit / list widget
\r
8577 GLT_DeSelectList()
\r
8579 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8582 // low-level front-end: append line to text edit / list widget
\r
8584 GLT_AddToList( char *name )
\r
8587 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8591 // low-level front-end: get line from text edit / list widget
\r
8593 GLT_GetFromList( int index, char *name )
\r
8596 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8602 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8604 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8605 int idx2 = idx1 + delta;
\r
8606 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8608 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8611 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8612 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8613 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8614 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8618 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8622 case WM_INITDIALOG:
\r
8623 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8625 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8626 Translate(hDlg, DLG_GameListOptions);
\r
8628 /* Initialize list */
\r
8629 GLT_TagsToList( lpUserGLT );
\r
8631 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8636 switch( LOWORD(wParam) ) {
\r
8639 EndDialog( hDlg, 0 );
\r
8642 EndDialog( hDlg, 1 );
\r
8645 case IDC_GLT_Default:
\r
8646 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8649 case IDC_GLT_Restore:
\r
8650 GLT_TagsToList( appData.gameListTags );
\r
8654 GLT_MoveSelection( hDlg, -1 );
\r
8657 case IDC_GLT_Down:
\r
8658 GLT_MoveSelection( hDlg, +1 );
\r
8668 int GameListOptions()
\r
8671 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8673 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8675 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8677 if( result == 0 ) {
\r
8678 /* [AS] Memory leak here! */
\r
8679 appData.gameListTags = strdup( lpUserGLT );
\r
8686 DisplayIcsInteractionTitle(char *str)
\r
8688 char consoleTitle[MSG_SIZ];
\r
8690 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8691 SetWindowText(hwndConsole, consoleTitle);
\r
8693 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8694 char buf[MSG_SIZ], *p = buf, *q;
\r
8695 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8697 q = strchr(p, ';');
\r
8699 if(*p) ChatPopUp(p);
\r
8703 SetActiveWindow(hwndMain);
\r
8707 DrawPosition(int fullRedraw, Board board)
\r
8709 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8712 void NotifyFrontendLogin()
\r
8715 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8721 fromX = fromY = -1;
\r
8722 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8723 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8724 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8725 dragInfo.lastpos = dragInfo.pos;
\r
8726 dragInfo.start.x = dragInfo.start.y = -1;
\r
8727 dragInfo.from = dragInfo.start;
\r
8729 DrawPosition(TRUE, NULL);
\r
8736 CommentPopUp(char *title, char *str)
\r
8738 HWND hwnd = GetActiveWindow();
\r
8739 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8741 SetActiveWindow(hwnd);
\r
8745 CommentPopDown(void)
\r
8747 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8748 if (commentDialog) {
\r
8749 ShowWindow(commentDialog, SW_HIDE);
\r
8751 commentUp = FALSE;
\r
8755 EditCommentPopUp(int index, char *title, char *str)
\r
8757 EitherCommentPopUp(index, title, str, TRUE);
\r
8764 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8771 MyPlaySound(&sounds[(int)SoundMove]);
\r
8774 VOID PlayIcsWinSound()
\r
8776 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8779 VOID PlayIcsLossSound()
\r
8781 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8784 VOID PlayIcsDrawSound()
\r
8786 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8789 VOID PlayIcsUnfinishedSound()
\r
8791 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8797 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8803 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8811 consoleEcho = TRUE;
\r
8812 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8813 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8814 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8823 consoleEcho = FALSE;
\r
8824 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8825 /* This works OK: set text and background both to the same color */
\r
8827 cf.crTextColor = COLOR_ECHOOFF;
\r
8828 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8829 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8832 /* No Raw()...? */
\r
8834 void Colorize(ColorClass cc, int continuation)
\r
8836 currentColorClass = cc;
\r
8837 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8838 consoleCF.crTextColor = textAttribs[cc].color;
\r
8839 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8840 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8846 static char buf[MSG_SIZ];
\r
8847 DWORD bufsiz = MSG_SIZ;
\r
8849 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8850 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8852 if (!GetUserName(buf, &bufsiz)) {
\r
8853 /*DisplayError("Error getting user name", GetLastError());*/
\r
8854 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8862 static char buf[MSG_SIZ];
\r
8863 DWORD bufsiz = MSG_SIZ;
\r
8865 if (!GetComputerName(buf, &bufsiz)) {
\r
8866 /*DisplayError("Error getting host name", GetLastError());*/
\r
8867 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8874 ClockTimerRunning()
\r
8876 return clockTimerEvent != 0;
\r
8882 if (clockTimerEvent == 0) return FALSE;
\r
8883 KillTimer(hwndMain, clockTimerEvent);
\r
8884 clockTimerEvent = 0;
\r
8889 StartClockTimer(long millisec)
\r
8891 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8892 (UINT) millisec, NULL);
\r
8896 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8899 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8901 if(appData.noGUI) return;
\r
8902 hdc = GetDC(hwndMain);
\r
8903 if (!IsIconic(hwndMain)) {
\r
8904 DisplayAClock(hdc, timeRemaining, highlight,
\r
8905 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8907 if (highlight && iconCurrent == iconBlack) {
\r
8908 iconCurrent = iconWhite;
\r
8909 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8910 if (IsIconic(hwndMain)) {
\r
8911 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8914 (void) ReleaseDC(hwndMain, hdc);
\r
8916 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8920 DisplayBlackClock(long timeRemaining, int highlight)
\r
8923 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8926 if(appData.noGUI) return;
\r
8927 hdc = GetDC(hwndMain);
\r
8928 if (!IsIconic(hwndMain)) {
\r
8929 DisplayAClock(hdc, timeRemaining, highlight,
\r
8930 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8932 if (highlight && iconCurrent == iconWhite) {
\r
8933 iconCurrent = iconBlack;
\r
8934 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8935 if (IsIconic(hwndMain)) {
\r
8936 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8939 (void) ReleaseDC(hwndMain, hdc);
\r
8941 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8946 LoadGameTimerRunning()
\r
8948 return loadGameTimerEvent != 0;
\r
8952 StopLoadGameTimer()
\r
8954 if (loadGameTimerEvent == 0) return FALSE;
\r
8955 KillTimer(hwndMain, loadGameTimerEvent);
\r
8956 loadGameTimerEvent = 0;
\r
8961 StartLoadGameTimer(long millisec)
\r
8963 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8964 (UINT) millisec, NULL);
\r
8972 char fileTitle[MSG_SIZ];
\r
8974 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8975 f = OpenFileDialog(hwndMain, "a", defName,
\r
8976 appData.oldSaveStyle ? "gam" : "pgn",
\r
8978 _("Save Game to File"), NULL, fileTitle, NULL);
\r
8980 SaveGame(f, 0, "");
\r
8987 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8989 if (delayedTimerEvent != 0) {
\r
8990 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
8991 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8993 KillTimer(hwndMain, delayedTimerEvent);
\r
8994 delayedTimerEvent = 0;
\r
8995 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
8996 delayedTimerCallback();
\r
8998 delayedTimerCallback = cb;
\r
8999 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9000 (UINT) millisec, NULL);
\r
9003 DelayedEventCallback
\r
9006 if (delayedTimerEvent) {
\r
9007 return delayedTimerCallback;
\r
9014 CancelDelayedEvent()
\r
9016 if (delayedTimerEvent) {
\r
9017 KillTimer(hwndMain, delayedTimerEvent);
\r
9018 delayedTimerEvent = 0;
\r
9022 DWORD GetWin32Priority(int nice)
\r
9023 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9025 REALTIME_PRIORITY_CLASS 0x00000100
\r
9026 HIGH_PRIORITY_CLASS 0x00000080
\r
9027 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9028 NORMAL_PRIORITY_CLASS 0x00000020
\r
9029 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9030 IDLE_PRIORITY_CLASS 0x00000040
\r
9032 if (nice < -15) return 0x00000080;
\r
9033 if (nice < 0) return 0x00008000;
\r
9034 if (nice == 0) return 0x00000020;
\r
9035 if (nice < 15) return 0x00004000;
\r
9036 return 0x00000040;
\r
9039 void RunCommand(char *cmdLine)
\r
9041 /* Now create the child process. */
\r
9042 STARTUPINFO siStartInfo;
\r
9043 PROCESS_INFORMATION piProcInfo;
\r
9045 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9046 siStartInfo.lpReserved = NULL;
\r
9047 siStartInfo.lpDesktop = NULL;
\r
9048 siStartInfo.lpTitle = NULL;
\r
9049 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9050 siStartInfo.cbReserved2 = 0;
\r
9051 siStartInfo.lpReserved2 = NULL;
\r
9052 siStartInfo.hStdInput = NULL;
\r
9053 siStartInfo.hStdOutput = NULL;
\r
9054 siStartInfo.hStdError = NULL;
\r
9056 CreateProcess(NULL,
\r
9057 cmdLine, /* command line */
\r
9058 NULL, /* process security attributes */
\r
9059 NULL, /* primary thread security attrs */
\r
9060 TRUE, /* handles are inherited */
\r
9061 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9062 NULL, /* use parent's environment */
\r
9064 &siStartInfo, /* STARTUPINFO pointer */
\r
9065 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9067 CloseHandle(piProcInfo.hThread);
\r
9070 /* Start a child process running the given program.
\r
9071 The process's standard output can be read from "from", and its
\r
9072 standard input can be written to "to".
\r
9073 Exit with fatal error if anything goes wrong.
\r
9074 Returns an opaque pointer that can be used to destroy the process
\r
9078 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9080 #define BUFSIZE 4096
\r
9082 HANDLE hChildStdinRd, hChildStdinWr,
\r
9083 hChildStdoutRd, hChildStdoutWr;
\r
9084 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9085 SECURITY_ATTRIBUTES saAttr;
\r
9087 PROCESS_INFORMATION piProcInfo;
\r
9088 STARTUPINFO siStartInfo;
\r
9090 char buf[MSG_SIZ];
\r
9093 if (appData.debugMode) {
\r
9094 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9099 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9100 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9101 saAttr.bInheritHandle = TRUE;
\r
9102 saAttr.lpSecurityDescriptor = NULL;
\r
9105 * The steps for redirecting child's STDOUT:
\r
9106 * 1. Create anonymous pipe to be STDOUT for child.
\r
9107 * 2. Create a noninheritable duplicate of read handle,
\r
9108 * and close the inheritable read handle.
\r
9111 /* Create a pipe for the child's STDOUT. */
\r
9112 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9113 return GetLastError();
\r
9116 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9117 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9118 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9119 FALSE, /* not inherited */
\r
9120 DUPLICATE_SAME_ACCESS);
\r
9122 return GetLastError();
\r
9124 CloseHandle(hChildStdoutRd);
\r
9127 * The steps for redirecting child's STDIN:
\r
9128 * 1. Create anonymous pipe to be STDIN for child.
\r
9129 * 2. Create a noninheritable duplicate of write handle,
\r
9130 * and close the inheritable write handle.
\r
9133 /* Create a pipe for the child's STDIN. */
\r
9134 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9135 return GetLastError();
\r
9138 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9139 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9140 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9141 FALSE, /* not inherited */
\r
9142 DUPLICATE_SAME_ACCESS);
\r
9144 return GetLastError();
\r
9146 CloseHandle(hChildStdinWr);
\r
9148 /* Arrange to (1) look in dir for the child .exe file, and
\r
9149 * (2) have dir be the child's working directory. Interpret
\r
9150 * dir relative to the directory WinBoard loaded from. */
\r
9151 GetCurrentDirectory(MSG_SIZ, buf);
\r
9152 SetCurrentDirectory(installDir);
\r
9153 SetCurrentDirectory(dir);
\r
9155 /* Now create the child process. */
\r
9157 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9158 siStartInfo.lpReserved = NULL;
\r
9159 siStartInfo.lpDesktop = NULL;
\r
9160 siStartInfo.lpTitle = NULL;
\r
9161 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9162 siStartInfo.cbReserved2 = 0;
\r
9163 siStartInfo.lpReserved2 = NULL;
\r
9164 siStartInfo.hStdInput = hChildStdinRd;
\r
9165 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9166 siStartInfo.hStdError = hChildStdoutWr;
\r
9168 fSuccess = CreateProcess(NULL,
\r
9169 cmdLine, /* command line */
\r
9170 NULL, /* process security attributes */
\r
9171 NULL, /* primary thread security attrs */
\r
9172 TRUE, /* handles are inherited */
\r
9173 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9174 NULL, /* use parent's environment */
\r
9176 &siStartInfo, /* STARTUPINFO pointer */
\r
9177 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9179 err = GetLastError();
\r
9180 SetCurrentDirectory(buf); /* return to prev directory */
\r
9185 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9186 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9187 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9190 /* Close the handles we don't need in the parent */
\r
9191 CloseHandle(piProcInfo.hThread);
\r
9192 CloseHandle(hChildStdinRd);
\r
9193 CloseHandle(hChildStdoutWr);
\r
9195 /* Prepare return value */
\r
9196 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9197 cp->kind = CPReal;
\r
9198 cp->hProcess = piProcInfo.hProcess;
\r
9199 cp->pid = piProcInfo.dwProcessId;
\r
9200 cp->hFrom = hChildStdoutRdDup;
\r
9201 cp->hTo = hChildStdinWrDup;
\r
9203 *pr = (void *) cp;
\r
9205 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9206 2000 where engines sometimes don't see the initial command(s)
\r
9207 from WinBoard and hang. I don't understand how that can happen,
\r
9208 but the Sleep is harmless, so I've put it in. Others have also
\r
9209 reported what may be the same problem, so hopefully this will fix
\r
9210 it for them too. */
\r
9218 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9220 ChildProc *cp; int result;
\r
9222 cp = (ChildProc *) pr;
\r
9223 if (cp == NULL) return;
\r
9225 switch (cp->kind) {
\r
9227 /* TerminateProcess is considered harmful, so... */
\r
9228 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9229 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9230 /* The following doesn't work because the chess program
\r
9231 doesn't "have the same console" as WinBoard. Maybe
\r
9232 we could arrange for this even though neither WinBoard
\r
9233 nor the chess program uses a console for stdio? */
\r
9234 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9236 /* [AS] Special termination modes for misbehaving programs... */
\r
9237 if( signal & 8 ) {
\r
9238 result = TerminateProcess( cp->hProcess, 0 );
\r
9240 if ( appData.debugMode) {
\r
9241 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9244 else if( signal & 4 ) {
\r
9245 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9247 if( dw != WAIT_OBJECT_0 ) {
\r
9248 result = TerminateProcess( cp->hProcess, 0 );
\r
9250 if ( appData.debugMode) {
\r
9251 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9257 CloseHandle(cp->hProcess);
\r
9261 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9265 closesocket(cp->sock);
\r
9270 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9271 closesocket(cp->sock);
\r
9272 closesocket(cp->sock2);
\r
9280 InterruptChildProcess(ProcRef pr)
\r
9284 cp = (ChildProc *) pr;
\r
9285 if (cp == NULL) return;
\r
9286 switch (cp->kind) {
\r
9288 /* The following doesn't work because the chess program
\r
9289 doesn't "have the same console" as WinBoard. Maybe
\r
9290 we could arrange for this even though neither WinBoard
\r
9291 nor the chess program uses a console for stdio */
\r
9292 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9297 /* Can't interrupt */
\r
9301 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9308 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9310 char cmdLine[MSG_SIZ];
\r
9312 if (port[0] == NULLCHAR) {
\r
9313 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9315 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9317 return StartChildProcess(cmdLine, "", pr);
\r
9321 /* Code to open TCP sockets */
\r
9324 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9330 struct sockaddr_in sa, mysa;
\r
9331 struct hostent FAR *hp;
\r
9332 unsigned short uport;
\r
9333 WORD wVersionRequested;
\r
9336 /* Initialize socket DLL */
\r
9337 wVersionRequested = MAKEWORD(1, 1);
\r
9338 err = WSAStartup(wVersionRequested, &wsaData);
\r
9339 if (err != 0) return err;
\r
9342 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9343 err = WSAGetLastError();
\r
9348 /* Bind local address using (mostly) don't-care values.
\r
9350 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9351 mysa.sin_family = AF_INET;
\r
9352 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9353 uport = (unsigned short) 0;
\r
9354 mysa.sin_port = htons(uport);
\r
9355 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9356 == SOCKET_ERROR) {
\r
9357 err = WSAGetLastError();
\r
9362 /* Resolve remote host name */
\r
9363 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9364 if (!(hp = gethostbyname(host))) {
\r
9365 unsigned int b0, b1, b2, b3;
\r
9367 err = WSAGetLastError();
\r
9369 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9370 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9371 hp->h_addrtype = AF_INET;
\r
9373 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9374 hp->h_addr_list[0] = (char *) malloc(4);
\r
9375 hp->h_addr_list[0][0] = (char) b0;
\r
9376 hp->h_addr_list[0][1] = (char) b1;
\r
9377 hp->h_addr_list[0][2] = (char) b2;
\r
9378 hp->h_addr_list[0][3] = (char) b3;
\r
9384 sa.sin_family = hp->h_addrtype;
\r
9385 uport = (unsigned short) atoi(port);
\r
9386 sa.sin_port = htons(uport);
\r
9387 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9389 /* Make connection */
\r
9390 if (connect(s, (struct sockaddr *) &sa,
\r
9391 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9392 err = WSAGetLastError();
\r
9397 /* Prepare return value */
\r
9398 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9399 cp->kind = CPSock;
\r
9401 *pr = (ProcRef *) cp;
\r
9407 OpenCommPort(char *name, ProcRef *pr)
\r
9412 char fullname[MSG_SIZ];
\r
9414 if (*name != '\\')
\r
9415 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9417 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9419 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9420 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9421 if (h == (HANDLE) -1) {
\r
9422 return GetLastError();
\r
9426 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9428 /* Accumulate characters until a 100ms pause, then parse */
\r
9429 ct.ReadIntervalTimeout = 100;
\r
9430 ct.ReadTotalTimeoutMultiplier = 0;
\r
9431 ct.ReadTotalTimeoutConstant = 0;
\r
9432 ct.WriteTotalTimeoutMultiplier = 0;
\r
9433 ct.WriteTotalTimeoutConstant = 0;
\r
9434 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9436 /* Prepare return value */
\r
9437 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9438 cp->kind = CPComm;
\r
9441 *pr = (ProcRef *) cp;
\r
9447 OpenLoopback(ProcRef *pr)
\r
9449 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9455 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9460 struct sockaddr_in sa, mysa;
\r
9461 struct hostent FAR *hp;
\r
9462 unsigned short uport;
\r
9463 WORD wVersionRequested;
\r
9466 char stderrPortStr[MSG_SIZ];
\r
9468 /* Initialize socket DLL */
\r
9469 wVersionRequested = MAKEWORD(1, 1);
\r
9470 err = WSAStartup(wVersionRequested, &wsaData);
\r
9471 if (err != 0) return err;
\r
9473 /* Resolve remote host name */
\r
9474 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9475 if (!(hp = gethostbyname(host))) {
\r
9476 unsigned int b0, b1, b2, b3;
\r
9478 err = WSAGetLastError();
\r
9480 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9481 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9482 hp->h_addrtype = AF_INET;
\r
9484 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9485 hp->h_addr_list[0] = (char *) malloc(4);
\r
9486 hp->h_addr_list[0][0] = (char) b0;
\r
9487 hp->h_addr_list[0][1] = (char) b1;
\r
9488 hp->h_addr_list[0][2] = (char) b2;
\r
9489 hp->h_addr_list[0][3] = (char) b3;
\r
9495 sa.sin_family = hp->h_addrtype;
\r
9496 uport = (unsigned short) 514;
\r
9497 sa.sin_port = htons(uport);
\r
9498 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9500 /* Bind local socket to unused "privileged" port address
\r
9502 s = INVALID_SOCKET;
\r
9503 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9504 mysa.sin_family = AF_INET;
\r
9505 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9506 for (fromPort = 1023;; fromPort--) {
\r
9507 if (fromPort < 0) {
\r
9509 return WSAEADDRINUSE;
\r
9511 if (s == INVALID_SOCKET) {
\r
9512 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9513 err = WSAGetLastError();
\r
9518 uport = (unsigned short) fromPort;
\r
9519 mysa.sin_port = htons(uport);
\r
9520 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9521 == SOCKET_ERROR) {
\r
9522 err = WSAGetLastError();
\r
9523 if (err == WSAEADDRINUSE) continue;
\r
9527 if (connect(s, (struct sockaddr *) &sa,
\r
9528 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9529 err = WSAGetLastError();
\r
9530 if (err == WSAEADDRINUSE) {
\r
9541 /* Bind stderr local socket to unused "privileged" port address
\r
9543 s2 = INVALID_SOCKET;
\r
9544 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9545 mysa.sin_family = AF_INET;
\r
9546 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9547 for (fromPort = 1023;; fromPort--) {
\r
9548 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9549 if (fromPort < 0) {
\r
9550 (void) closesocket(s);
\r
9552 return WSAEADDRINUSE;
\r
9554 if (s2 == INVALID_SOCKET) {
\r
9555 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9556 err = WSAGetLastError();
\r
9562 uport = (unsigned short) fromPort;
\r
9563 mysa.sin_port = htons(uport);
\r
9564 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9565 == SOCKET_ERROR) {
\r
9566 err = WSAGetLastError();
\r
9567 if (err == WSAEADDRINUSE) continue;
\r
9568 (void) closesocket(s);
\r
9572 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9573 err = WSAGetLastError();
\r
9574 if (err == WSAEADDRINUSE) {
\r
9576 s2 = INVALID_SOCKET;
\r
9579 (void) closesocket(s);
\r
9580 (void) closesocket(s2);
\r
9586 prevStderrPort = fromPort; // remember port used
\r
9587 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9589 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9590 err = WSAGetLastError();
\r
9591 (void) closesocket(s);
\r
9592 (void) closesocket(s2);
\r
9597 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9598 err = WSAGetLastError();
\r
9599 (void) closesocket(s);
\r
9600 (void) closesocket(s2);
\r
9604 if (*user == NULLCHAR) user = UserName();
\r
9605 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9606 err = WSAGetLastError();
\r
9607 (void) closesocket(s);
\r
9608 (void) closesocket(s2);
\r
9612 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9613 err = WSAGetLastError();
\r
9614 (void) closesocket(s);
\r
9615 (void) closesocket(s2);
\r
9620 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9621 err = WSAGetLastError();
\r
9622 (void) closesocket(s);
\r
9623 (void) closesocket(s2);
\r
9627 (void) closesocket(s2); /* Stop listening */
\r
9629 /* Prepare return value */
\r
9630 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9631 cp->kind = CPRcmd;
\r
9634 *pr = (ProcRef *) cp;
\r
9641 AddInputSource(ProcRef pr, int lineByLine,
\r
9642 InputCallback func, VOIDSTAR closure)
\r
9644 InputSource *is, *is2 = NULL;
\r
9645 ChildProc *cp = (ChildProc *) pr;
\r
9647 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9648 is->lineByLine = lineByLine;
\r
9650 is->closure = closure;
\r
9651 is->second = NULL;
\r
9652 is->next = is->buf;
\r
9653 if (pr == NoProc) {
\r
9654 is->kind = CPReal;
\r
9655 consoleInputSource = is;
\r
9657 is->kind = cp->kind;
\r
9659 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9660 we create all threads suspended so that the is->hThread variable can be
\r
9661 safely assigned, then let the threads start with ResumeThread.
\r
9663 switch (cp->kind) {
\r
9665 is->hFile = cp->hFrom;
\r
9666 cp->hFrom = NULL; /* now owned by InputThread */
\r
9668 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9669 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9673 is->hFile = cp->hFrom;
\r
9674 cp->hFrom = NULL; /* now owned by InputThread */
\r
9676 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9677 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9681 is->sock = cp->sock;
\r
9683 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9684 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9688 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9690 is->sock = cp->sock;
\r
9692 is2->sock = cp->sock2;
\r
9693 is2->second = is2;
\r
9695 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9696 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9698 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9699 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9703 if( is->hThread != NULL ) {
\r
9704 ResumeThread( is->hThread );
\r
9707 if( is2 != NULL && is2->hThread != NULL ) {
\r
9708 ResumeThread( is2->hThread );
\r
9712 return (InputSourceRef) is;
\r
9716 RemoveInputSource(InputSourceRef isr)
\r
9720 is = (InputSource *) isr;
\r
9721 is->hThread = NULL; /* tell thread to stop */
\r
9722 CloseHandle(is->hThread);
\r
9723 if (is->second != NULL) {
\r
9724 is->second->hThread = NULL;
\r
9725 CloseHandle(is->second->hThread);
\r
9729 int no_wrap(char *message, int count)
\r
9731 ConsoleOutput(message, count, FALSE);
\r
9736 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9739 int outCount = SOCKET_ERROR;
\r
9740 ChildProc *cp = (ChildProc *) pr;
\r
9741 static OVERLAPPED ovl;
\r
9742 static int line = 0;
\r
9746 if (appData.noJoin || !appData.useInternalWrap)
\r
9747 return no_wrap(message, count);
\r
9750 int width = get_term_width();
\r
9751 int len = wrap(NULL, message, count, width, &line);
\r
9752 char *msg = malloc(len);
\r
9756 return no_wrap(message, count);
\r
9759 dbgchk = wrap(msg, message, count, width, &line);
\r
9760 if (dbgchk != len && appData.debugMode)
\r
9761 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9762 ConsoleOutput(msg, len, FALSE);
\r
9769 if (ovl.hEvent == NULL) {
\r
9770 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9772 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9774 switch (cp->kind) {
\r
9777 outCount = send(cp->sock, message, count, 0);
\r
9778 if (outCount == SOCKET_ERROR) {
\r
9779 *outError = WSAGetLastError();
\r
9781 *outError = NO_ERROR;
\r
9786 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9787 &dOutCount, NULL)) {
\r
9788 *outError = NO_ERROR;
\r
9789 outCount = (int) dOutCount;
\r
9791 *outError = GetLastError();
\r
9796 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9797 &dOutCount, &ovl);
\r
9798 if (*outError == NO_ERROR) {
\r
9799 outCount = (int) dOutCount;
\r
9809 if(n != 0) Sleep(n);
\r
9813 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9816 /* Ignore delay, not implemented for WinBoard */
\r
9817 return OutputToProcess(pr, message, count, outError);
\r
9822 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9823 char *buf, int count, int error)
\r
9825 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9828 /* see wgamelist.c for Game List functions */
\r
9829 /* see wedittags.c for Edit Tags functions */
\r
9836 char buf[MSG_SIZ];
\r
9839 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9840 f = fopen(buf, "r");
\r
9842 ProcessICSInitScript(f);
\r
9852 StartAnalysisClock()
\r
9854 if (analysisTimerEvent) return;
\r
9855 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9856 (UINT) 2000, NULL);
\r
9860 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9862 highlightInfo.sq[0].x = fromX;
\r
9863 highlightInfo.sq[0].y = fromY;
\r
9864 highlightInfo.sq[1].x = toX;
\r
9865 highlightInfo.sq[1].y = toY;
\r
9871 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9872 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9876 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9878 premoveHighlightInfo.sq[0].x = fromX;
\r
9879 premoveHighlightInfo.sq[0].y = fromY;
\r
9880 premoveHighlightInfo.sq[1].x = toX;
\r
9881 premoveHighlightInfo.sq[1].y = toY;
\r
9885 ClearPremoveHighlights()
\r
9887 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9888 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9892 ShutDownFrontEnd()
\r
9894 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9895 DeleteClipboardTempFiles();
\r
9901 if (IsIconic(hwndMain))
\r
9902 ShowWindow(hwndMain, SW_RESTORE);
\r
9904 SetActiveWindow(hwndMain);
\r
9908 * Prototypes for animation support routines
\r
9910 static void ScreenSquare(int column, int row, POINT * pt);
\r
9911 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9912 POINT frames[], int * nFrames);
\r
9918 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9919 { // [HGM] atomic: animate blast wave
\r
9922 explodeInfo.fromX = fromX;
\r
9923 explodeInfo.fromY = fromY;
\r
9924 explodeInfo.toX = toX;
\r
9925 explodeInfo.toY = toY;
\r
9926 for(i=1; i<4*kFactor; i++) {
\r
9927 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9928 DrawPosition(FALSE, board);
\r
9929 Sleep(appData.animSpeed);
\r
9931 explodeInfo.radius = 0;
\r
9932 DrawPosition(TRUE, board);
\r
9936 AnimateMove(board, fromX, fromY, toX, toY)
\r
9943 ChessSquare piece;
\r
9944 int x = toX, y = toY;
\r
9945 POINT start, finish, mid;
\r
9946 POINT frames[kFactor * 2 + 1];
\r
9949 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
9951 if (!appData.animate) return;
\r
9952 if (doingSizing) return;
\r
9953 if (fromY < 0 || fromX < 0) return;
\r
9954 piece = board[fromY][fromX];
\r
9955 if (piece >= EmptySquare) return;
\r
9957 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
9961 ScreenSquare(fromX, fromY, &start);
\r
9962 ScreenSquare(toX, toY, &finish);
\r
9964 /* All moves except knight jumps move in straight line */
\r
9965 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
9966 mid.x = start.x + (finish.x - start.x) / 2;
\r
9967 mid.y = start.y + (finish.y - start.y) / 2;
\r
9969 /* Knight: make straight movement then diagonal */
\r
9970 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9971 mid.x = start.x + (finish.x - start.x) / 2;
\r
9975 mid.y = start.y + (finish.y - start.y) / 2;
\r
9979 /* Don't use as many frames for very short moves */
\r
9980 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9981 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9983 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9985 animInfo.from.x = fromX;
\r
9986 animInfo.from.y = fromY;
\r
9987 animInfo.to.x = toX;
\r
9988 animInfo.to.y = toY;
\r
9989 animInfo.lastpos = start;
\r
9990 animInfo.piece = piece;
\r
9991 for (n = 0; n < nFrames; n++) {
\r
9992 animInfo.pos = frames[n];
\r
9993 DrawPosition(FALSE, NULL);
\r
9994 animInfo.lastpos = animInfo.pos;
\r
9995 Sleep(appData.animSpeed);
\r
9997 animInfo.pos = finish;
\r
9998 DrawPosition(FALSE, NULL);
\r
10000 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10002 animInfo.piece = EmptySquare;
\r
10003 Explode(board, fromX, fromY, toX, toY);
\r
10006 /* Convert board position to corner of screen rect and color */
\r
10009 ScreenSquare(column, row, pt)
\r
10010 int column; int row; POINT * pt;
\r
10013 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10014 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10016 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10017 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10021 /* Generate a series of frame coords from start->mid->finish.
\r
10022 The movement rate doubles until the half way point is
\r
10023 reached, then halves back down to the final destination,
\r
10024 which gives a nice slow in/out effect. The algorithmn
\r
10025 may seem to generate too many intermediates for short
\r
10026 moves, but remember that the purpose is to attract the
\r
10027 viewers attention to the piece about to be moved and
\r
10028 then to where it ends up. Too few frames would be less
\r
10032 Tween(start, mid, finish, factor, frames, nFrames)
\r
10033 POINT * start; POINT * mid;
\r
10034 POINT * finish; int factor;
\r
10035 POINT frames[]; int * nFrames;
\r
10037 int n, fraction = 1, count = 0;
\r
10039 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10040 for (n = 0; n < factor; n++)
\r
10042 for (n = 0; n < factor; n++) {
\r
10043 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10044 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10046 fraction = fraction / 2;
\r
10050 frames[count] = *mid;
\r
10053 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10055 for (n = 0; n < factor; n++) {
\r
10056 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10057 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10059 fraction = fraction * 2;
\r
10061 *nFrames = count;
\r
10065 SettingsPopUp(ChessProgramState *cps)
\r
10066 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10067 EngineOptionsPopup(savedHwnd, cps);
\r
10070 int flock(int fid, int code)
\r
10072 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10074 ov.hEvent = NULL;
\r
10076 ov.OffsetHigh = 0;
\r
10078 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10079 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10080 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10081 default: return -1;
\r
10090 static char col[8][20];
\r
10091 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10093 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10098 ActivateTheme (int new)
\r
10099 { // Redo initialization of features depending on options that can occur in themes
\r
10101 if(new) InitDrawingColors();
\r
10102 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10103 InitDrawingSizes(boardSize, 0);
\r
10104 InvalidateRect(hwndMain, NULL, TRUE);
\r