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, 2015 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;
\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,
\r
264 OPT_Ranget, IDOK, IDCANCEL },
\r
265 { DLG_SaveOptions, OPT_Autosave, OPT_AVPrompt, OPT_AVToFile, OPT_AVBrowse,
\r
266 801, OPT_PGN, OPT_Old, OPT_OutOfBookInfo, IDOK, IDCANCEL },
\r
267 { 1536, 1090, IDC_Directories, 1089, 1091, IDOK, IDCANCEL, 1038, IDC_IndexNr, 1037 },
\r
268 { DLG_CommPort, IDOK, IDCANCEL, IDC_Port, IDC_Rate, IDC_Bits, IDC_Parity,
\r
269 IDC_Stop, IDC_Flow, OPT_SerialHelp },
\r
270 { DLG_EditComment, IDOK, OPT_CancelComment, OPT_ClearComment, OPT_EditComment },
\r
271 { DLG_PromotionKing, PB_Chancellor, PB_Archbishop, PB_Queen, PB_Rook,
\r
272 PB_Bishop, PB_Knight, PB_King, IDCANCEL, IDC_Yes, IDC_No, IDC_Centaur },
\r
273 { ABOUTBOX2, IDC_ChessBoard },
\r
274 { DLG_GameList, OPT_GameListLoad, OPT_GameListPrev, OPT_GameListNext,
\r
275 OPT_GameListClose, IDC_GameListDoFilter },
\r
276 { DLG_EditTags, IDOK, OPT_TagsCancel, OPT_EditTags },
\r
277 { DLG_Error, IDOK },
\r
278 { DLG_Colorize, IDOK, IDCANCEL, OPT_ChooseColor, OPT_Bold, OPT_Italic,
\r
279 OPT_Underline, OPT_Strikeout, OPT_Sample },
\r
280 { DLG_Question, IDOK, IDCANCEL, OPT_QuestionText },
\r
281 { DLG_Startup, IDC_Welcome, OPT_ChessEngine, OPT_ChessServer, OPT_View,
\r
282 IDC_SPECIFY_ENG_STATIC, IDC_SPECIFY_SERVER_STATIC, OPT_AnyAdditional,
\r
283 IDOK, IDCANCEL, IDM_HELPCONTENTS },
\r
284 { DLG_IndexNumber, IDC_Index },
\r
285 { DLG_TypeInMove, IDOK, IDCANCEL },
\r
286 { DLG_TypeInName, IDOK, IDCANCEL },
\r
287 { DLG_Sound, IDC_Event, OPT_NoSound, OPT_DefaultBeep, OPT_BuiltInSound,
\r
288 OPT_WavFile, OPT_BrowseSound, OPT_DefaultSounds, IDOK, IDCANCEL, OPT_PlaySound },
\r
289 { DLG_GeneralOptions, IDOK, IDCANCEL, OPT_AlwaysOnTop, OPT_HighlightLastMove,
\r
290 OPT_AlwaysQueen, OPT_PeriodicUpdates, OPT_AnimateDragging, OPT_PonderNextMove,
\r
291 OPT_AnimateMoving, OPT_PopupExitMessage, OPT_AutoFlag, OPT_PopupMoveErrors,
\r
292 OPT_AutoFlipView, OPT_ShowButtonBar, OPT_AutoRaiseBoard, OPT_ShowCoordinates,
\r
293 OPT_Blindfold, OPT_ShowThinking, OPT_HighlightDragging, OPT_TestLegality,
\r
294 OPT_SaveExtPGN, OPT_HideThinkFromHuman, OPT_ExtraInfoInMoveHistory,
\r
295 OPT_HighlightMoveArrow, OPT_AutoLogo ,OPT_SmartMove },
\r
296 { DLG_IcsOptions, IDOK, IDCANCEL, OPT_AutoComment, OPT_AutoKibitz, OPT_AutoObserve,
\r
297 OPT_GetMoveList, OPT_LocalLineEditing, OPT_QuietPlay, OPT_SeekGraph, OPT_AutoRefresh,
\r
298 OPT_BgObserve, OPT_DualBoard, OPT_Premove, OPT_PremoveWhite, OPT_PremoveBlack,
\r
299 OPT_SmartMove, OPT_IcsAlarm, IDC_Sec, OPT_ChooseShoutColor, OPT_ChooseSShoutColor,
\r
300 OPT_ChooseChannel1Color, OPT_ChooseChannelColor, OPT_ChooseKibitzColor,
\r
301 OPT_ChooseTellColor, OPT_ChooseChallengeColor, OPT_ChooseRequestColor,
\r
302 OPT_ChooseSeekColor, OPT_ChooseNormalColor, OPT_ChooseBackgroundColor,
\r
303 OPT_DefaultColors, OPT_DontColorize, IDC_Boxes, GPB_Colors, GPB_Premove,
\r
304 GPB_General, GPB_Alarm, OPT_AutoCreate },
\r
305 { DLG_BoardOptions, IDOK, IDCANCEL, OPT_SizeTiny, OPT_SizeTeeny, OPT_SizeDinky,
\r
306 OPT_SizePetite, OPT_SizeSlim, OPT_SizeSmall, OPT_SizeMediocre, OPT_SizeMiddling,
\r
307 OPT_SizeAverage, OPT_SizeModerate, OPT_SizeMedium, OPT_SizeBulky, OPT_SizeLarge,
\r
308 OPT_SizeBig, OPT_SizeHuge, OPT_SizeGiant, OPT_SizeColossal, OPT_SizeTitanic,
\r
309 OPT_ChooseLightSquareColor, OPT_ChooseDarkSquareColor, OPT_ChooseWhitePieceColor,
\r
310 OPT_ChooseBlackPieceColor, OPT_ChooseHighlightSquareColor, OPT_ChoosePremoveHighlightColor,
\r
311 OPT_Monochrome, OPT_AllWhite, OPT_UpsideDown, OPT_DefaultBoardColors, GPB_Colors,
\r
312 IDC_Light, IDC_Dark, IDC_White, IDC_Black, IDC_High, IDC_PreHigh, GPB_Size, OPT_Bitmaps, OPT_PieceFont, OPT_Grid },
\r
313 { DLG_NewVariant, IDOK, IDCANCEL, OPT_VariantNormal, OPT_VariantFRC, OPT_VariantWildcastle,
\r
314 OPT_VariantNocastle, OPT_VariantLosers, OPT_VariantGiveaway, OPT_VariantSuicide,
\r
315 OPT_Variant3Check, OPT_VariantTwoKings, OPT_VariantAtomic, OPT_VariantCrazyhouse,
\r
316 OPT_VariantBughouse, OPT_VariantTwilight, OPT_VariantShogi, OPT_VariantSuper,
\r
317 OPT_VariantKnightmate, OPT_VariantBerolina, OPT_VariantCylinder, OPT_VariantFairy,
\r
318 OPT_VariantMakruk, OPT_VariantGothic, OPT_VariantCapablanca, OPT_VariantJanus,
\r
319 OPT_VariantCRC, OPT_VariantFalcon, OPT_VariantCourier, OPT_VariantGreat, OPT_VariantSChess,
\r
320 OPT_VariantShatranj, OPT_VariantXiangqi, GPB_Variant, GPB_Board, IDC_Height,
\r
321 IDC_Width, IDC_Hand, IDC_Pieces, IDC_Def },
\r
322 { DLG_Fonts, IDOK, IDCANCEL, OPT_ChooseClockFont, OPT_ChooseMessageFont,
\r
323 OPT_ChooseCoordFont, OPT_ChooseTagFont, OPT_ChooseCommentsFont, OPT_ChooseConsoleFont, OPT_ChooseMoveHistoryFont, OPT_DefaultFonts,
\r
324 OPT_ClockFont, OPT_MessageFont, OPT_CoordFont, OPT_EditTagsFont, OPT_ChoosePieceFont, OPT_MessageFont8,
\r
325 OPT_SampleGameListFont, OPT_ChooseGameListFont, OPT_MessageFont7,
\r
326 OPT_CommentsFont, OPT_MessageFont5, GPB_Current, GPB_All, OPT_MessageFont6 },
\r
327 { DLG_NewGameFRC, IDC_NFG_Label, IDC_NFG_Random, IDOK, IDCANCEL },
\r
328 { DLG_GameListOptions, IDC_GLT, IDC_GLT_Up, IDC_GLT_Down, IDC_GLT_Restore,
\r
329 IDC_GLT_Default, IDOK, IDCANCEL, IDC_GLT_RestoreTo },
\r
330 { DLG_MoveHistory },
\r
331 { DLG_EvalGraph },
\r
332 { DLG_EngineOutput, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineLabel2, IDC_Engine2_NPS },
\r
333 { DLG_Chat, IDC_Partner, IDC_Clear, IDC_Send, },
\r
334 { DLG_EnginePlayOptions, IDC_EpPonder, IDC_EpShowThinking, IDC_EpHideThinkingHuman,
\r
335 IDC_EpPeriodicUpdates, GPB_Adjudications, IDC_Draw, IDC_Moves, IDC_Threshold,
\r
336 IDC_Centi, IDC_TestClaims, IDC_DetectMates, IDC_MaterialDraws, IDC_TrivialDraws,
\r
337 GPB_Apply, IDC_Rule, IDC_Repeats, IDC_ScoreAbs1, IDC_ScoreAbs2, IDOK, IDCANCEL },
\r
338 { DLG_OptionsUCI, IDC_PolyDir, IDC_BrowseForPolyglotDir, IDC_Hash, IDC_Path,
\r
339 IDC_BrowseForEGTB, IDC_Cache, IDC_UseBook, IDC_BrowseForBook, IDC_CPU, IDC_OwnBook1,
\r
340 IDC_OwnBook2, IDC_Depth, IDC_Variation, IDC_DefGames, IDOK, IDCANCEL },
\r
344 static char languageBuf[70000], *foreign[1000], *english[1000], *languageFile[MSG_SIZ];
\r
345 static int lastChecked;
\r
346 static char oldLanguage[MSG_SIZ], *menuText[10][30];
\r
347 extern int tinyLayout;
\r
348 extern char * menuBarText[][10];
\r
351 LoadLanguageFile(char *name)
\r
352 { //load the file with translations, and make a list of the strings to be translated, and their translations
\r
354 int i=0, j=0, n=0, k;
\r
357 if(!name || name[0] == NULLCHAR) return;
\r
358 snprintf(buf, MSG_SIZ, "%s%s", name, strchr(name, '.') ? "" : ".lng"); // auto-append lng extension
\r
359 appData.language = oldLanguage;
\r
360 if(!strcmp(buf, oldLanguage)) { barbaric = 1; return; } // this language already loaded; just switch on
\r
361 if((f = fopen(buf, "r")) == NULL) return;
\r
362 while((k = fgetc(f)) != EOF) {
\r
363 if(i >= sizeof(languageBuf)) { DisplayError("Language file too big", 0); return; }
\r
364 languageBuf[i] = k;
\r
366 if(languageBuf[n] == '"' && languageBuf[i-1] == '"') {
\r
368 if(p = strstr(languageBuf + n + 1, "\" === \"")) {
\r
369 if(p > languageBuf+n+2 && p+8 < languageBuf+i) {
\r
370 if(j >= sizeof(english)) { DisplayError("Too many translated strings", 0); return; }
\r
371 english[j] = languageBuf + n + 1; *p = 0;
\r
372 foreign[j++] = p + 7; languageBuf[i-1] = 0;
\r
373 //if(appData.debugMode) fprintf(debugFP, "translation: replace '%s' by '%s'\n", english[j-1], foreign[j-1]);
\r
378 } else if(i > 0 && languageBuf[i-1] == '\\') {
\r
380 case 'n': k = '\n'; break;
\r
381 case 'r': k = '\r'; break;
\r
382 case 't': k = '\t'; break;
\r
384 languageBuf[--i] = k;
\r
389 barbaric = (j != 0);
\r
390 safeStrCpy(oldLanguage, buf, sizeof(oldLanguage)/sizeof(oldLanguage[0]) );
\r
395 { // return the translation of the given string
\r
396 // efficiency can be improved a lot...
\r
398 static char buf[MSG_SIZ];
\r
399 //if(appData.debugMode) fprintf(debugFP, "T_(%s)\n", s);
\r
400 if(!barbaric) return s;
\r
401 if(!s) return ""; // sanity
\r
402 while(english[i]) {
\r
403 if(!strcmp(s, english[i])) return foreign[i];
\r
404 if(english[i][0] == '%' && strstr(s, english[i]+1) == s) { // allow translation of strings with variable ending
\r
405 snprintf(buf, MSG_SIZ, "%s%s", foreign[i], s + strlen(english[i]+1)); // keep unmatched portion
\r
414 Translate(HWND hDlg, int dialogID)
\r
415 { // translate all text items in the given dialog
\r
417 char buf[MSG_SIZ], *s;
\r
418 if(!barbaric) return;
\r
419 while(dialogItems[i][0] && dialogItems[i][0] != dialogID) i++; // find the dialog description
\r
420 if(dialogItems[i][0] != dialogID) return; // unknown dialog, should not happen
\r
421 GetWindowText( hDlg, buf, MSG_SIZ );
\r
423 if(strcmp(buf, s)) SetWindowText(hDlg, s); // replace by translated string (if different)
\r
424 for(j=1; k=dialogItems[i][j]; j++) { // translate all listed dialog items
\r
425 GetDlgItemText(hDlg, k, buf, MSG_SIZ);
\r
426 if(strlen(buf) == 0) continue;
\r
428 if(strcmp(buf, s)) SetDlgItemText(hDlg, k, s); // replace by translated string (if different)
\r
433 TranslateOneMenu(int i, HMENU subMenu)
\r
436 static MENUITEMINFO info;
\r
438 info.cbSize = sizeof(MENUITEMINFO);
\r
439 info.fMask = MIIM_STATE | MIIM_TYPE;
\r
440 for(j=GetMenuItemCount(subMenu)-1; j>=0; j--){
\r
442 info.dwTypeData = buf;
\r
443 info.cch = sizeof(buf);
\r
444 GetMenuItemInfo(subMenu, j, TRUE, &info);
\r
446 if(menuText[i][j]) safeStrCpy(buf, menuText[i][j], sizeof(buf)/sizeof(buf[0]) );
\r
447 else menuText[i][j] = strdup(buf); // remember original on first change
\r
449 if(buf[0] == NULLCHAR) continue;
\r
450 info.dwTypeData = T_(buf);
\r
451 info.cch = strlen(buf)+1;
\r
452 SetMenuItemInfo(subMenu, j, TRUE, &info);
\r
458 TranslateMenus(int addLanguage)
\r
461 WIN32_FIND_DATA fileData;
\r
463 #define IDM_English 1970
\r
465 HMENU mainMenu = GetMenu(hwndMain);
\r
466 for (i=GetMenuItemCount(mainMenu)-1; i>=0; i--) {
\r
467 HMENU subMenu = GetSubMenu(mainMenu, i);
\r
468 ModifyMenu(mainMenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP|EnableMenuItem(mainMenu, i, MF_BYPOSITION),
\r
469 (UINT) subMenu, T_(menuBarText[tinyLayout][i]));
\r
470 TranslateOneMenu(i, subMenu);
\r
472 DrawMenuBar(hwndMain);
\r
475 if(!addLanguage) return;
\r
476 if((hFind = FindFirstFile("*.LNG", &fileData)) != INVALID_HANDLE_VALUE) {
\r
477 HMENU mainMenu = GetMenu(hwndMain);
\r
478 HMENU subMenu = GetSubMenu(mainMenu, GetMenuItemCount(mainMenu)-1);
\r
479 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
480 AppendMenu(subMenu, MF_ENABLED|MF_STRING|(barbaric?MF_UNCHECKED:MF_CHECKED), (UINT_PTR) IDM_English, (LPCTSTR) "English");
\r
481 i = 0; lastChecked = IDM_English;
\r
483 char *p, *q = fileData.cFileName;
\r
484 int checkFlag = MF_UNCHECKED;
\r
485 languageFile[i] = strdup(q);
\r
486 if(barbaric && !strcmp(oldLanguage, q)) {
\r
487 checkFlag = MF_CHECKED;
\r
488 lastChecked = IDM_English + i + 1;
\r
489 CheckMenuItem(mainMenu, IDM_English, MF_BYCOMMAND|MF_UNCHECKED);
\r
491 *q = ToUpper(*q); while(*++q) *q = ToLower(*q);
\r
492 p = strstr(fileData.cFileName, ".lng");
\r
494 AppendMenu(subMenu, MF_ENABLED|MF_STRING|checkFlag, (UINT_PTR) IDM_English + ++i, (LPCTSTR) fileData.cFileName);
\r
495 } while(FindNextFile(hFind, &fileData));
\r
502 #define IDM_RecentEngines 3000
\r
505 RecentEngineMenu (char *s)
\r
507 if(appData.icsActive) return;
\r
508 if(appData.recentEngines > 0 && *s) { // feature is on, and list non-empty
\r
509 HMENU mainMenu = GetMenu(hwndMain);
\r
510 HMENU subMenu = GetSubMenu(mainMenu, 5); // Engine menu
\r
511 int i=IDM_RecentEngines;
\r
512 recentEngines = strdup(appData.recentEngineList); // remember them as they are in menu
\r
513 AppendMenu(subMenu, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
515 char *p = strchr(s, '\n');
\r
516 if(p == NULL) return; // malformed!
\r
518 AppendMenu(subMenu, MF_ENABLED|MF_STRING|MF_UNCHECKED, (UINT_PTR) i++, (LPCTSTR) s);
\r
532 int cliWidth, cliHeight;
\r
535 SizeInfo sizeInfo[] =
\r
537 { "tiny", 21, 0, 1, 2, 0, 0 },
\r
538 { "teeny", 25, 1, 1, 2, 0, 0 },
\r
539 { "dinky", 29, 1, 1, 2, 0, 0 },
\r
540 { "petite", 33, 1, 1, 2, 0, 0 },
\r
541 { "slim", 37, 2, 1, 1, 0, 0 },
\r
542 { "small", 40, 2, 1, 1, 0, 0 },
\r
543 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
544 { "middling", 49, 2, 0, 0, 0, 0 },
\r
545 { "average", 54, 2, 0, 0, 0, 0 },
\r
546 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
547 { "medium", 64, 3, 0, 0, 0, 0 },
\r
548 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
549 { "large", 80, 3, 0, 0, 0, 0 },
\r
550 { "big", 87, 3, 0, 0, 0, 0 },
\r
551 { "huge", 95, 3, 0, 0, 0, 0 },
\r
552 { "giant", 108, 3, 0, 0, 0, 0 },
\r
553 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
554 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
555 { NULL, 0, 0, 0, 0, 0, 0 }
\r
558 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
559 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
561 { 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
562 { 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
563 { 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
564 { 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
565 { 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
566 { 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
567 { 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
568 { 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
569 { 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
570 { 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
571 { 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
572 { 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
573 { 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
574 { 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
575 { 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
576 { 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
577 { 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
578 { 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
581 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
590 #define BUTTON_WIDTH (tinyLayout == 2 ? 16 : 32)
\r
591 #define N_BUTTONS 5
\r
593 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
595 {"<<", IDM_ToStart, NULL, NULL},
\r
596 {"<", IDM_Backward, NULL, NULL},
\r
597 {"P", IDM_Pause, NULL, NULL},
\r
598 {">", IDM_Forward, NULL, NULL},
\r
599 {">>", IDM_ToEnd, NULL, NULL},
\r
602 int tinyLayout = 0, smallLayout = 0;
\r
603 #define MENU_BAR_ITEMS 9
\r
604 char *menuBarText[3][MENU_BAR_ITEMS+1] = {
\r
605 { N_("&File"), N_("&Edit"), N_("&View"), N_("&Mode"), N_("&Action"), N_("E&ngine"), N_("&Options"), N_("&Help"), NULL },
\r
606 { N_("&Fil"), N_("&Ed"), N_("&Vw"), N_("&Mod"), N_("&Act"), N_("E&ng"), N_("&Opt"), N_("&Hlp"), NULL },
\r
607 { N_("&F"), N_("&E"), N_("&V"), N_("&M"), N_("&A"), N_("&N"), N_("&O"), N_("&H"), NULL },
\r
611 MySound sounds[(int)NSoundClasses];
\r
612 MyTextAttribs textAttribs[(int)NColorClasses];
\r
614 MyColorizeAttribs colorizeAttribs[] = {
\r
615 { (COLORREF)0, 0, N_("Shout Text") },
\r
616 { (COLORREF)0, 0, N_("SShout/CShout") },
\r
617 { (COLORREF)0, 0, N_("Channel 1 Text") },
\r
618 { (COLORREF)0, 0, N_("Channel Text") },
\r
619 { (COLORREF)0, 0, N_("Kibitz Text") },
\r
620 { (COLORREF)0, 0, N_("Tell Text") },
\r
621 { (COLORREF)0, 0, N_("Challenge Text") },
\r
622 { (COLORREF)0, 0, N_("Request Text") },
\r
623 { (COLORREF)0, 0, N_("Seek Text") },
\r
624 { (COLORREF)0, 0, N_("Normal Text") },
\r
625 { (COLORREF)0, 0, N_("None") }
\r
630 static char *commentTitle;
\r
631 static char *commentText;
\r
632 static int commentIndex;
\r
633 static Boolean editComment = FALSE;
\r
636 char errorTitle[MSG_SIZ];
\r
637 char errorMessage[2*MSG_SIZ];
\r
638 HWND errorDialog = NULL;
\r
639 BOOLEAN moveErrorMessageUp = FALSE;
\r
640 BOOLEAN consoleEcho = TRUE;
\r
641 CHARFORMAT consoleCF;
\r
642 COLORREF consoleBackgroundColor;
\r
644 char *programVersion;
\r
650 typedef int CPKind;
\r
659 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
662 #define INPUT_SOURCE_BUF_SIZE 4096
\r
664 typedef struct _InputSource {
\r
671 char buf[INPUT_SOURCE_BUF_SIZE];
\r
675 InputCallback func;
\r
676 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
680 InputSource *consoleInputSource;
\r
685 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
686 VOID ConsoleCreate();
\r
688 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
689 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
690 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
691 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
693 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
694 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
695 void ParseIcsTextMenu(char *icsTextMenuString);
\r
696 VOID PopUpNameDialog(char firstchar);
\r
697 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
701 int GameListOptions();
\r
703 int dummy; // [HGM] for obsolete args
\r
705 HWND hwndMain = NULL; /* root window*/
\r
706 HWND hwndConsole = NULL;
\r
707 HWND commentDialog = NULL;
\r
708 HWND moveHistoryDialog = NULL;
\r
709 HWND evalGraphDialog = NULL;
\r
710 HWND engineOutputDialog = NULL;
\r
711 HWND gameListDialog = NULL;
\r
712 HWND editTagsDialog = NULL;
\r
714 int commentUp = FALSE;
\r
716 WindowPlacement wpMain;
\r
717 WindowPlacement wpConsole;
\r
718 WindowPlacement wpComment;
\r
719 WindowPlacement wpMoveHistory;
\r
720 WindowPlacement wpEvalGraph;
\r
721 WindowPlacement wpEngineOutput;
\r
722 WindowPlacement wpGameList;
\r
723 WindowPlacement wpTags;
\r
725 VOID EngineOptionsPopup(); // [HGM] settings
\r
727 VOID GothicPopUp(char *title, VariantClass variant);
\r
729 * Setting "frozen" should disable all user input other than deleting
\r
730 * the window. We do this while engines are initializing themselves.
\r
732 static int frozen = 0;
\r
733 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
739 if (frozen) return;
\r
741 hmenu = GetMenu(hwndMain);
\r
742 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
743 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
745 DrawMenuBar(hwndMain);
\r
748 /* Undo a FreezeUI */
\r
754 if (!frozen) return;
\r
756 hmenu = GetMenu(hwndMain);
\r
757 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
758 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
760 DrawMenuBar(hwndMain);
\r
763 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
765 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
771 #define JAWS_ALT_INTERCEPT
\r
772 #define JAWS_KBUP_NAVIGATION
\r
773 #define JAWS_KBDOWN_NAVIGATION
\r
774 #define JAWS_MENU_ITEMS
\r
775 #define JAWS_SILENCE
\r
776 #define JAWS_REPLAY
\r
778 #define JAWS_COPYRIGHT
\r
779 #define JAWS_DELETE(X) X
\r
780 #define SAYMACHINEMOVE()
\r
784 /*---------------------------------------------------------------------------*\
\r
788 \*---------------------------------------------------------------------------*/
\r
790 static void HandleMessage P((MSG *message));
\r
791 static HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
794 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
795 LPSTR lpCmdLine, int nCmdShow)
\r
798 // INITCOMMONCONTROLSEX ex;
\r
802 LoadLibrary("RICHED32.DLL");
\r
803 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
805 if (!InitApplication(hInstance)) {
\r
808 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
815 // InitCommonControlsEx(&ex);
\r
816 InitCommonControls();
\r
818 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
819 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
820 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
822 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
824 while (GetMessage(&msg, /* message structure */
\r
825 NULL, /* handle of window receiving the message */
\r
826 0, /* lowest message to examine */
\r
827 0)) /* highest message to examine */
\r
829 HandleMessage(&msg);
\r
833 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
837 HandleMessage (MSG *message)
\r
839 MSG msg = *message;
\r
841 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
842 // [HGM] navigate: switch between all windows with tab
\r
843 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
844 int i, currentElement = 0;
\r
846 // first determine what element of the chain we come from (if any)
\r
847 if(appData.icsActive) {
\r
848 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
849 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
851 if(engineOutputDialog && EngineOutputIsUp()) {
\r
852 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
853 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
855 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
856 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
858 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
859 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
860 if(msg.hwnd == e1) currentElement = 2; else
\r
861 if(msg.hwnd == e2) currentElement = 3; else
\r
862 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
863 if(msg.hwnd == mh) currentElement = 4; else
\r
864 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
865 if(msg.hwnd == hText) currentElement = 5; else
\r
866 if(msg.hwnd == hInput) currentElement = 6; else
\r
867 for (i = 0; i < N_BUTTONS; i++) {
\r
868 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
871 // determine where to go to
\r
872 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
874 currentElement = (currentElement + direction) % 7;
\r
875 switch(currentElement) {
\r
877 h = hwndMain; break; // passing this case always makes the loop exit
\r
879 h = buttonDesc[0].hwnd; break; // could be NULL
\r
881 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
884 if(!EngineOutputIsUp()) continue;
\r
887 if(!MoveHistoryIsUp()) continue;
\r
889 // case 6: // input to eval graph does not seem to get here!
\r
890 // if(!EvalGraphIsUp()) continue;
\r
891 // h = evalGraphDialog; break;
\r
893 if(!appData.icsActive) continue;
\r
897 if(!appData.icsActive) continue;
\r
903 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
904 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
907 return; // this message now has been processed
\r
911 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
912 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
913 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
914 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
915 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
916 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
917 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
918 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
919 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
920 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
921 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
922 for(i=0; i<MAX_CHAT; i++)
\r
923 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
926 if(done) return; // [HGM] chat: end patch
\r
927 TranslateMessage(&msg); /* Translates virtual key codes */
\r
928 DispatchMessage(&msg); /* Dispatches message to window */
\r
934 { /* Dispatch pending messages */
\r
936 while (PeekMessage(&msg, /* message structure */
\r
937 NULL, /* handle of window receiving the message */
\r
938 0, /* lowest message to examine */
\r
939 0, /* highest message to examine */
\r
942 HandleMessage(&msg);
\r
946 /*---------------------------------------------------------------------------*\
\r
948 * Initialization functions
\r
950 \*---------------------------------------------------------------------------*/
\r
954 { // update user logo if necessary
\r
955 static char oldUserName[MSG_SIZ], dir[MSG_SIZ], *curName;
\r
957 if(appData.autoLogo) {
\r
958 curName = UserName();
\r
959 if(strcmp(curName, oldUserName)) {
\r
960 GetCurrentDirectory(MSG_SIZ, dir);
\r
961 SetCurrentDirectory(installDir);
\r
962 snprintf(oldUserName, MSG_SIZ, "logos\\%s.bmp", curName);
\r
963 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
964 safeStrCpy(oldUserName, curName, sizeof(oldUserName)/sizeof(oldUserName[0]) );
\r
965 if(userLogo == NULL)
\r
966 userLogo = LoadImage( 0, "logos\\dummy.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
967 SetCurrentDirectory(dir); /* return to prev directory */
\r
973 InitApplication(HINSTANCE hInstance)
\r
977 /* Fill in window class structure with parameters that describe the */
\r
980 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
981 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
982 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
983 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
984 wc.hInstance = hInstance; /* Owner of this class */
\r
985 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
986 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
987 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
988 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
989 wc.lpszClassName = szAppName; /* Name to register as */
\r
991 /* Register the window class and return success/failure code. */
\r
992 if (!RegisterClass(&wc)) return FALSE;
\r
994 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
995 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
997 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
998 wc.hInstance = hInstance;
\r
999 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
1000 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
1001 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
1002 wc.lpszMenuName = NULL;
\r
1003 wc.lpszClassName = szConsoleName;
\r
1005 if (!RegisterClass(&wc)) return FALSE;
\r
1010 /* Set by InitInstance, used by EnsureOnScreen */
\r
1011 int screenHeight, screenWidth;
\r
1012 RECT screenGeometry;
\r
1015 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
1017 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
1018 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
1019 if (*x > screenGeometry.right - 32) *x = screenGeometry.left;
\r
1020 if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;
\r
1021 if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;
\r
1022 if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;
\r
1026 LoadLogo(ChessProgramState *cps, int n, Boolean ics)
\r
1028 char buf[MSG_SIZ], dir[MSG_SIZ];
\r
1029 GetCurrentDirectory(MSG_SIZ, dir);
\r
1030 SetCurrentDirectory(installDir);
\r
1031 if( appData.logo[n] && appData.logo[n][0] != NULLCHAR) {
\r
1032 cps->programLogo = LoadImage( 0, appData.logo[n], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1034 if (cps->programLogo == NULL && appData.debugMode) {
\r
1035 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.logo[n] );
\r
1037 } else if(appData.autoLogo) {
\r
1038 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
\r
1039 char *opponent = "";
\r
1040 if(gameMode == IcsPlayingWhite) opponent = gameInfo.black;
\r
1041 if(gameMode == IcsPlayingBlack) opponent = gameInfo.white;
\r
1042 sprintf(buf, "logos\\%s\\%s.bmp", appData.icsHost, opponent);
\r
1043 if(!*opponent || !(cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ))) {
\r
1044 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
1045 cps->programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1048 if(appData.directory[n] && appData.directory[n][0]) {
\r
1049 SetCurrentDirectory(appData.directory[n]);
\r
1050 cps->programLogo = LoadImage( 0, "logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1053 SetCurrentDirectory(dir); /* return to prev directory */
\r
1059 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
1060 backTextureSquareSize = 0; // kludge to force recalculation of texturemode
\r
1062 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
1063 if(liteBackTexture) DeleteObject(liteBackTexture);
\r
1064 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1065 liteBackTextureMode = appData.liteBackTextureMode;
\r
1067 if (liteBackTexture == NULL && appData.debugMode) {
\r
1068 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
1072 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
1073 if(darkBackTexture) DeleteObject(darkBackTexture);
\r
1074 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
1075 darkBackTextureMode = appData.darkBackTextureMode;
\r
1077 if (darkBackTexture == NULL && appData.debugMode) {
\r
1078 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
1083 #ifndef SM_CXVIRTUALSCREEN
\r
1084 #define SM_CXVIRTUALSCREEN 78
\r
1086 #ifndef SM_CYVIRTUALSCREEN
\r
1087 #define SM_CYVIRTUALSCREEN 79
\r
1089 #ifndef SM_XVIRTUALSCREEN
\r
1090 #define SM_XVIRTUALSCREEN 76
\r
1092 #ifndef SM_YVIRTUALSCREEN
\r
1093 #define SM_YVIRTUALSCREEN 77
\r
1099 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
1100 if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
1101 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
1102 if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
1103 screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
\r
1104 screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
\r
1105 screenGeometry.right = screenGeometry.left + screenWidth;
\r
1106 screenGeometry.bottom = screenGeometry.top + screenHeight;
\r
1109 ChessProgramState broadcast;
\r
1112 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1114 HWND hwnd; /* Main window handle. */
\r
1116 WINDOWPLACEMENT wp;
\r
1119 hInst = hInstance; /* Store instance handle in our global variable */
\r
1120 programName = szAppName;
\r
1122 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1123 *filepart = NULLCHAR;
\r
1124 SetCurrentDirectory(installDir);
\r
1126 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1128 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1130 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1131 /* xboard, and older WinBoards, controlled the move sound with the
\r
1132 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1133 always turn the option on (so that the backend will call us),
\r
1134 then let the user turn the sound off by setting it to silence if
\r
1135 desired. To accommodate old winboard.ini files saved by old
\r
1136 versions of WinBoard, we also turn off the sound if the option
\r
1137 was initially set to false. [HGM] taken out of InitAppData */
\r
1138 if (!appData.ringBellAfterMoves) {
\r
1139 sounds[(int)SoundMove].name = strdup("");
\r
1140 appData.ringBellAfterMoves = TRUE;
\r
1142 if (appData.debugMode) {
\r
1143 char *c = appData.nameOfDebugFile;
\r
1144 if(strstr(c, "///") == c) {
\r
1145 broadcast.which = "broadcaster";
\r
1146 broadcast.pr = NoProc;
\r
1147 broadcast.isr = NULL;
\r
1148 broadcast.prog = c + 3;
\r
1149 broadcast.dir = ".";
\r
1150 broadcast.host = "localhost";
\r
1151 StartChessProgram(&broadcast);
\r
1152 debugFP = (FILE*) _fdopen(_open_osfhandle((long)(((ChildProc*)(broadcast.pr))->hTo), _O_WRONLY), "w");
\r
1154 debugFP = fopen(c, "w");
\r
1155 setbuf(debugFP, NULL);
\r
1158 LoadLanguageFile(appData.language);
\r
1162 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1163 // InitEngineUCI( installDir, &second );
\r
1165 /* Create a main window for this application instance. */
\r
1166 hwnd = CreateWindow(szAppName, szTitle,
\r
1167 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1168 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1169 NULL, NULL, hInstance, NULL);
\r
1172 /* If window could not be created, return "failure" */
\r
1177 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1178 LoadLogo(&first, 0, FALSE);
\r
1179 LoadLogo(&second, 1, appData.icsActive);
\r
1183 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1184 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1185 iconCurrent = iconWhite;
\r
1186 InitDrawingColors();
\r
1188 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1189 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1190 /* Compute window size for each board size, and use the largest
\r
1191 size that fits on this screen as the default. */
\r
1192 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1193 if (boardSize == (BoardSize)-1 &&
\r
1194 winH <= screenHeight
\r
1195 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1196 && winW <= screenWidth) {
\r
1197 boardSize = (BoardSize)ibs;
\r
1201 InitDrawingSizes(boardSize, 0);
\r
1202 RecentEngineMenu(appData.recentEngineList);
\r
1204 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1206 /* [AS] Load textures if specified */
\r
1209 mysrandom( (unsigned) time(NULL) );
\r
1211 /* [AS] Restore layout */
\r
1212 if( wpMoveHistory.visible ) {
\r
1213 MoveHistoryPopUp();
\r
1216 if( wpEvalGraph.visible ) {
\r
1220 if( wpEngineOutput.visible ) {
\r
1221 EngineOutputPopUp();
\r
1224 /* Make the window visible; update its client area; and return "success" */
\r
1225 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1226 wp.length = sizeof(WINDOWPLACEMENT);
\r
1228 wp.showCmd = nCmdShow;
\r
1229 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1230 wp.rcNormalPosition.left = wpMain.x;
\r
1231 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1232 wp.rcNormalPosition.top = wpMain.y;
\r
1233 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1234 SetWindowPlacement(hwndMain, &wp);
\r
1236 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1238 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1239 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1241 if (hwndConsole) {
\r
1243 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1244 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1246 ShowWindow(hwndConsole, nCmdShow);
\r
1247 SetActiveWindow(hwndConsole);
\r
1249 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1250 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1259 HMENU hmenu = GetMenu(hwndMain);
\r
1261 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1262 MF_BYCOMMAND|((appData.icsActive &&
\r
1263 *appData.icsCommPort != NULLCHAR) ?
\r
1264 MF_ENABLED : MF_GRAYED));
\r
1265 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1266 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1267 MF_CHECKED : MF_UNCHECKED));
\r
1268 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1271 //---------------------------------------------------------------------------------------------------------
\r
1273 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1274 #define XBOARD FALSE
\r
1276 #define OPTCHAR "/"
\r
1277 #define SEPCHAR "="
\r
1278 #define TOPLEVEL 0
\r
1282 // front-end part of option handling
\r
1285 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1287 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1288 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1291 lf->lfEscapement = 0;
\r
1292 lf->lfOrientation = 0;
\r
1293 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1294 lf->lfItalic = mfp->italic;
\r
1295 lf->lfUnderline = mfp->underline;
\r
1296 lf->lfStrikeOut = mfp->strikeout;
\r
1297 lf->lfCharSet = mfp->charset;
\r
1298 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1302 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1303 lf->lfQuality = DEFAULT_QUALITY;
\r
1304 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1305 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1309 CreateFontInMF(MyFont *mf)
\r
1311 LFfromMFP(&mf->lf, &mf->mfp);
\r
1312 if (mf->hf) DeleteObject(mf->hf);
\r
1313 mf->hf = CreateFontIndirect(&mf->lf);
\r
1316 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1318 colorVariable[] = {
\r
1319 &whitePieceColor,
\r
1320 &blackPieceColor,
\r
1321 &lightSquareColor,
\r
1322 &darkSquareColor,
\r
1323 &highlightSquareColor,
\r
1324 &premoveHighlightColor,
\r
1326 &consoleBackgroundColor,
\r
1327 &appData.fontForeColorWhite,
\r
1328 &appData.fontBackColorWhite,
\r
1329 &appData.fontForeColorBlack,
\r
1330 &appData.fontBackColorBlack,
\r
1331 &appData.evalHistColorWhite,
\r
1332 &appData.evalHistColorBlack,
\r
1333 &appData.highlightArrowColor,
\r
1336 /* Command line font name parser. NULL name means do nothing.
\r
1337 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1338 For backward compatibility, syntax without the colon is also
\r
1339 accepted, but font names with digits in them won't work in that case.
\r
1342 ParseFontName(char *name, MyFontParams *mfp)
\r
1345 if (name == NULL) return;
\r
1347 q = strchr(p, ':');
\r
1349 if (q - p >= sizeof(mfp->faceName))
\r
1350 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1351 memcpy(mfp->faceName, p, q - p);
\r
1352 mfp->faceName[q - p] = NULLCHAR;
\r
1355 q = mfp->faceName;
\r
1357 while (*p && !isdigit(*p)) {
\r
1359 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1360 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1362 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1365 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1366 mfp->pointSize = (float) atof(p);
\r
1367 mfp->bold = (strchr(p, 'b') != NULL);
\r
1368 mfp->italic = (strchr(p, 'i') != NULL);
\r
1369 mfp->underline = (strchr(p, 'u') != NULL);
\r
1370 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1371 mfp->charset = DEFAULT_CHARSET;
\r
1372 q = strchr(p, 'c');
\r
1374 mfp->charset = (BYTE) atoi(q+1);
\r
1378 ParseFont(char *name, int number)
\r
1379 { // wrapper to shield back-end from 'font'
\r
1380 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1385 { // in WB we have a 2D array of fonts; this initializes their description
\r
1387 /* Point font array elements to structures and
\r
1388 parse default font names */
\r
1389 for (i=0; i<NUM_FONTS; i++) {
\r
1390 for (j=0; j<NUM_SIZES; j++) {
\r
1391 font[j][i] = &fontRec[j][i];
\r
1392 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1399 { // here we create the actual fonts from the selected descriptions
\r
1401 for (i=0; i<NUM_FONTS; i++) {
\r
1402 for (j=0; j<NUM_SIZES; j++) {
\r
1403 CreateFontInMF(font[j][i]);
\r
1407 /* Color name parser.
\r
1408 X version accepts X color names, but this one
\r
1409 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1411 ParseColorName(char *name)
\r
1413 int red, green, blue, count;
\r
1414 char buf[MSG_SIZ];
\r
1416 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1418 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1419 &red, &green, &blue);
\r
1422 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1423 DisplayError(buf, 0);
\r
1424 return RGB(0, 0, 0);
\r
1426 return PALETTERGB(red, green, blue);
\r
1430 ParseColor(int n, char *name)
\r
1431 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1432 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1436 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1438 char *e = argValue;
\r
1442 if (*e == 'b') eff |= CFE_BOLD;
\r
1443 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1444 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1445 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1446 else if (*e == '#' || isdigit(*e)) break;
\r
1450 *color = ParseColorName(e);
\r
1454 ParseTextAttribs(ColorClass cc, char *s)
\r
1455 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1456 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1457 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1461 ParseBoardSize(void *addr, char *name)
\r
1462 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1463 BoardSize bs = SizeTiny;
\r
1464 while (sizeInfo[bs].name != NULL) {
\r
1465 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1466 *(BoardSize *)addr = bs;
\r
1471 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1476 { // [HGM] import name from appData first
\r
1479 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1480 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1481 textAttribs[cc].sound.data = NULL;
\r
1482 MyLoadSound(&textAttribs[cc].sound);
\r
1484 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1485 textAttribs[cc].sound.name = strdup("");
\r
1486 textAttribs[cc].sound.data = NULL;
\r
1488 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1489 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1490 sounds[sc].data = NULL;
\r
1491 MyLoadSound(&sounds[sc]);
\r
1496 SetCommPortDefaults()
\r
1498 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1499 dcb.DCBlength = sizeof(DCB);
\r
1500 dcb.BaudRate = 9600;
\r
1501 dcb.fBinary = TRUE;
\r
1502 dcb.fParity = FALSE;
\r
1503 dcb.fOutxCtsFlow = FALSE;
\r
1504 dcb.fOutxDsrFlow = FALSE;
\r
1505 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1506 dcb.fDsrSensitivity = FALSE;
\r
1507 dcb.fTXContinueOnXoff = TRUE;
\r
1508 dcb.fOutX = FALSE;
\r
1510 dcb.fNull = FALSE;
\r
1511 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1512 dcb.fAbortOnError = FALSE;
\r
1514 dcb.Parity = SPACEPARITY;
\r
1515 dcb.StopBits = ONESTOPBIT;
\r
1518 // [HGM] args: these three cases taken out to stay in front-end
\r
1520 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1521 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1522 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1523 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1525 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1526 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1527 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1528 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1529 ad->argName, mfp->faceName, mfp->pointSize,
\r
1530 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1531 mfp->bold ? "b" : "",
\r
1532 mfp->italic ? "i" : "",
\r
1533 mfp->underline ? "u" : "",
\r
1534 mfp->strikeout ? "s" : "",
\r
1535 (int)mfp->charset);
\r
1541 { // [HGM] copy the names from the internal WB variables to appData
\r
1544 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1545 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1546 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1547 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1551 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1552 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1553 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1554 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1555 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1556 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1557 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1558 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1559 (ta->effects) ? " " : "",
\r
1560 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1564 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1565 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1566 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1567 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1568 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1572 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1573 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1574 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1578 ParseCommPortSettings(char *s)
\r
1579 { // wrapper to keep dcb from back-end
\r
1580 ParseCommSettings(s, &dcb);
\r
1585 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1586 GetActualPlacement(hwndMain, &wpMain);
\r
1587 GetActualPlacement(hwndConsole, &wpConsole);
\r
1588 GetActualPlacement(commentDialog, &wpComment);
\r
1589 GetActualPlacement(editTagsDialog, &wpTags);
\r
1590 GetActualPlacement(gameListDialog, &wpGameList);
\r
1591 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1592 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1593 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1597 PrintCommPortSettings(FILE *f, char *name)
\r
1598 { // wrapper to shield back-end from DCB
\r
1599 PrintCommSettings(f, name, &dcb);
\r
1603 MySearchPath(char *installDir, char *name, char *fullname)
\r
1605 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1606 if(name[0]== '%') {
\r
1607 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1608 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1609 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1610 *strchr(buf, '%') = 0;
\r
1611 strcat(fullname, getenv(buf));
\r
1612 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1614 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1615 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1616 return (int) strlen(fullname);
\r
1618 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1622 MyGetFullPathName(char *name, char *fullname)
\r
1625 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1630 { // [HGM] args: allows testing if main window is realized from back-end
\r
1631 return hwndMain != NULL;
\r
1635 PopUpStartupDialog()
\r
1639 LoadLanguageFile(appData.language);
\r
1640 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1641 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1642 FreeProcInstance(lpProc);
\r
1645 /*---------------------------------------------------------------------------*\
\r
1647 * GDI board drawing routines
\r
1649 \*---------------------------------------------------------------------------*/
\r
1651 /* [AS] Draw square using background texture */
\r
1652 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1657 return; /* Should never happen! */
\r
1660 SetGraphicsMode( dst, GM_ADVANCED );
\r
1667 /* X reflection */
\r
1672 x.eDx = (FLOAT) dw + dx - 1;
\r
1675 SetWorldTransform( dst, &x );
\r
1678 /* Y reflection */
\r
1684 x.eDy = (FLOAT) dh + dy - 1;
\r
1686 SetWorldTransform( dst, &x );
\r
1694 x.eDx = (FLOAT) dx;
\r
1695 x.eDy = (FLOAT) dy;
\r
1698 SetWorldTransform( dst, &x );
\r
1702 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1710 SetWorldTransform( dst, &x );
\r
1712 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1715 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1717 PM_WP = (int) WhitePawn,
\r
1718 PM_WN = (int) WhiteKnight,
\r
1719 PM_WB = (int) WhiteBishop,
\r
1720 PM_WR = (int) WhiteRook,
\r
1721 PM_WQ = (int) WhiteQueen,
\r
1722 PM_WF = (int) WhiteFerz,
\r
1723 PM_WW = (int) WhiteWazir,
\r
1724 PM_WE = (int) WhiteAlfil,
\r
1725 PM_WM = (int) WhiteMan,
\r
1726 PM_WO = (int) WhiteCannon,
\r
1727 PM_WU = (int) WhiteUnicorn,
\r
1728 PM_WH = (int) WhiteNightrider,
\r
1729 PM_WA = (int) WhiteAngel,
\r
1730 PM_WC = (int) WhiteMarshall,
\r
1731 PM_WAB = (int) WhiteCardinal,
\r
1732 PM_WD = (int) WhiteDragon,
\r
1733 PM_WL = (int) WhiteLance,
\r
1734 PM_WS = (int) WhiteCobra,
\r
1735 PM_WV = (int) WhiteFalcon,
\r
1736 PM_WSG = (int) WhiteSilver,
\r
1737 PM_WG = (int) WhiteGrasshopper,
\r
1738 PM_WK = (int) WhiteKing,
\r
1739 PM_BP = (int) BlackPawn,
\r
1740 PM_BN = (int) BlackKnight,
\r
1741 PM_BB = (int) BlackBishop,
\r
1742 PM_BR = (int) BlackRook,
\r
1743 PM_BQ = (int) BlackQueen,
\r
1744 PM_BF = (int) BlackFerz,
\r
1745 PM_BW = (int) BlackWazir,
\r
1746 PM_BE = (int) BlackAlfil,
\r
1747 PM_BM = (int) BlackMan,
\r
1748 PM_BO = (int) BlackCannon,
\r
1749 PM_BU = (int) BlackUnicorn,
\r
1750 PM_BH = (int) BlackNightrider,
\r
1751 PM_BA = (int) BlackAngel,
\r
1752 PM_BC = (int) BlackMarshall,
\r
1753 PM_BG = (int) BlackGrasshopper,
\r
1754 PM_BAB = (int) BlackCardinal,
\r
1755 PM_BD = (int) BlackDragon,
\r
1756 PM_BL = (int) BlackLance,
\r
1757 PM_BS = (int) BlackCobra,
\r
1758 PM_BV = (int) BlackFalcon,
\r
1759 PM_BSG = (int) BlackSilver,
\r
1760 PM_BK = (int) BlackKing
\r
1763 static HFONT hPieceFont = NULL;
\r
1764 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1765 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1766 static int fontBitmapSquareSize = 0;
\r
1767 static char pieceToFontChar[(int) EmptySquare] =
\r
1768 { 'p', 'n', 'b', 'r', 'q',
\r
1769 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1770 'k', 'o', 'm', 'v', 't', 'w',
\r
1771 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1774 extern BOOL SetCharTable( char *table, const char * map );
\r
1775 /* [HGM] moved to backend.c */
\r
1777 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1780 BYTE r1 = GetRValue( color );
\r
1781 BYTE g1 = GetGValue( color );
\r
1782 BYTE b1 = GetBValue( color );
\r
1788 /* Create a uniform background first */
\r
1789 hbrush = CreateSolidBrush( color );
\r
1790 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1791 FillRect( hdc, &rc, hbrush );
\r
1792 DeleteObject( hbrush );
\r
1795 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1796 int steps = squareSize / 2;
\r
1799 for( i=0; i<steps; i++ ) {
\r
1800 BYTE r = r1 - (r1-r2) * i / steps;
\r
1801 BYTE g = g1 - (g1-g2) * i / steps;
\r
1802 BYTE b = b1 - (b1-b2) * i / steps;
\r
1804 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1805 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1806 FillRect( hdc, &rc, hbrush );
\r
1807 DeleteObject(hbrush);
\r
1810 else if( mode == 2 ) {
\r
1811 /* Diagonal gradient, good more or less for every piece */
\r
1812 POINT triangle[3];
\r
1813 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1814 HBRUSH hbrush_old;
\r
1815 int steps = squareSize;
\r
1818 triangle[0].x = squareSize - steps;
\r
1819 triangle[0].y = squareSize;
\r
1820 triangle[1].x = squareSize;
\r
1821 triangle[1].y = squareSize;
\r
1822 triangle[2].x = squareSize;
\r
1823 triangle[2].y = squareSize - steps;
\r
1825 for( i=0; i<steps; i++ ) {
\r
1826 BYTE r = r1 - (r1-r2) * i / steps;
\r
1827 BYTE g = g1 - (g1-g2) * i / steps;
\r
1828 BYTE b = b1 - (b1-b2) * i / steps;
\r
1830 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1831 hbrush_old = SelectObject( hdc, hbrush );
\r
1832 Polygon( hdc, triangle, 3 );
\r
1833 SelectObject( hdc, hbrush_old );
\r
1834 DeleteObject(hbrush);
\r
1839 SelectObject( hdc, hpen );
\r
1844 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1845 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1846 piece: follow the steps as explained below.
\r
1848 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1852 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1858 int backColor = whitePieceColor;
\r
1859 int foreColor = blackPieceColor;
\r
1861 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1862 backColor = appData.fontBackColorWhite;
\r
1863 foreColor = appData.fontForeColorWhite;
\r
1865 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1866 backColor = appData.fontBackColorBlack;
\r
1867 foreColor = appData.fontForeColorBlack;
\r
1871 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1873 hbm_old = SelectObject( hdc, hbm );
\r
1877 rc.right = squareSize;
\r
1878 rc.bottom = squareSize;
\r
1880 /* Step 1: background is now black */
\r
1881 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1883 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1885 pt.x = (squareSize - sz.cx) / 2;
\r
1886 pt.y = (squareSize - sz.cy) / 2;
\r
1888 SetBkMode( hdc, TRANSPARENT );
\r
1889 SetTextColor( hdc, chroma );
\r
1890 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1891 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1893 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1894 /* Step 3: the area outside the piece is filled with white */
\r
1895 // FloodFill( hdc, 0, 0, chroma );
\r
1896 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1897 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1898 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1899 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1900 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1902 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1903 but if the start point is not inside the piece we're lost!
\r
1904 There should be a better way to do this... if we could create a region or path
\r
1905 from the fill operation we would be fine for example.
\r
1907 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1908 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1910 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1911 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1912 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1914 SelectObject( dc2, bm2 );
\r
1915 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1916 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1917 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1918 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1919 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1922 DeleteObject( bm2 );
\r
1925 SetTextColor( hdc, 0 );
\r
1927 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1928 draw the piece again in black for safety.
\r
1930 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1932 SelectObject( hdc, hbm_old );
\r
1934 if( hPieceMask[index] != NULL ) {
\r
1935 DeleteObject( hPieceMask[index] );
\r
1938 hPieceMask[index] = hbm;
\r
1941 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1943 SelectObject( hdc, hbm );
\r
1946 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1947 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1948 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1950 SelectObject( dc1, hPieceMask[index] );
\r
1951 SelectObject( dc2, bm2 );
\r
1952 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1953 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1956 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1957 the piece background and deletes (makes transparent) the rest.
\r
1958 Thanks to that mask, we are free to paint the background with the greates
\r
1959 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1960 We use this, to make gradients and give the pieces a "roundish" look.
\r
1962 SetPieceBackground( hdc, backColor, 2 );
\r
1963 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1967 DeleteObject( bm2 );
\r
1970 SetTextColor( hdc, foreColor );
\r
1971 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1973 SelectObject( hdc, hbm_old );
\r
1975 if( hPieceFace[index] != NULL ) {
\r
1976 DeleteObject( hPieceFace[index] );
\r
1979 hPieceFace[index] = hbm;
\r
1982 static int TranslatePieceToFontPiece( int piece )
\r
2012 case BlackMarshall:
\r
2016 case BlackNightrider:
\r
2022 case BlackUnicorn:
\r
2026 case BlackGrasshopper:
\r
2038 case BlackCardinal:
\r
2045 case WhiteMarshall:
\r
2049 case WhiteNightrider:
\r
2055 case WhiteUnicorn:
\r
2059 case WhiteGrasshopper:
\r
2071 case WhiteCardinal:
\r
2080 void CreatePiecesFromFont()
\r
2083 HDC hdc_window = NULL;
\r
2089 if( fontBitmapSquareSize < 0 ) {
\r
2090 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2094 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2095 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2096 fontBitmapSquareSize = -1;
\r
2100 if( fontBitmapSquareSize != squareSize ) {
\r
2101 hdc_window = GetDC( hwndMain );
\r
2102 hdc = CreateCompatibleDC( hdc_window );
\r
2104 if( hPieceFont != NULL ) {
\r
2105 DeleteObject( hPieceFont );
\r
2108 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2109 hPieceMask[i] = NULL;
\r
2110 hPieceFace[i] = NULL;
\r
2116 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2117 fontHeight = appData.fontPieceSize;
\r
2120 fontHeight = (fontHeight * squareSize) / 100;
\r
2122 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2124 lf.lfEscapement = 0;
\r
2125 lf.lfOrientation = 0;
\r
2126 lf.lfWeight = FW_NORMAL;
\r
2128 lf.lfUnderline = 0;
\r
2129 lf.lfStrikeOut = 0;
\r
2130 lf.lfCharSet = DEFAULT_CHARSET;
\r
2131 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2132 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2133 lf.lfQuality = PROOF_QUALITY;
\r
2134 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2135 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2136 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2138 hPieceFont = CreateFontIndirect( &lf );
\r
2140 if( hPieceFont == NULL ) {
\r
2141 fontBitmapSquareSize = -2;
\r
2144 /* Setup font-to-piece character table */
\r
2145 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2146 /* No (or wrong) global settings, try to detect the font */
\r
2147 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2149 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2151 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2152 /* DiagramTT* family */
\r
2153 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2155 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2156 /* Fairy symbols */
\r
2157 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2159 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2160 /* Good Companion (Some characters get warped as literal :-( */
\r
2161 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2162 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2163 SetCharTable(pieceToFontChar, s);
\r
2166 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2167 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2171 /* Create bitmaps */
\r
2172 hfont_old = SelectObject( hdc, hPieceFont );
\r
2173 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2174 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2175 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2177 SelectObject( hdc, hfont_old );
\r
2179 fontBitmapSquareSize = squareSize;
\r
2183 if( hdc != NULL ) {
\r
2187 if( hdc_window != NULL ) {
\r
2188 ReleaseDC( hwndMain, hdc_window );
\r
2193 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2195 char name[128], buf[MSG_SIZ];
\r
2197 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2198 if(appData.pieceDirectory[0]) {
\r
2200 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2201 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2202 if(res) return res;
\r
2204 if (gameInfo.event &&
\r
2205 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2206 strcmp(name, "k80s") == 0) {
\r
2207 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2209 return LoadBitmap(hinst, name);
\r
2213 /* Insert a color into the program's logical palette
\r
2214 structure. This code assumes the given color is
\r
2215 the result of the RGB or PALETTERGB macro, and it
\r
2216 knows how those macros work (which is documented).
\r
2219 InsertInPalette(COLORREF color)
\r
2221 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2223 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2224 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2225 pLogPal->palNumEntries--;
\r
2229 pe->peFlags = (char) 0;
\r
2230 pe->peRed = (char) (0xFF & color);
\r
2231 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2232 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2238 InitDrawingColors()
\r
2241 if (pLogPal == NULL) {
\r
2242 /* Allocate enough memory for a logical palette with
\r
2243 * PALETTESIZE entries and set the size and version fields
\r
2244 * of the logical palette structure.
\r
2246 pLogPal = (NPLOGPALETTE)
\r
2247 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2248 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2249 pLogPal->palVersion = 0x300;
\r
2251 pLogPal->palNumEntries = 0;
\r
2253 InsertInPalette(lightSquareColor);
\r
2254 InsertInPalette(darkSquareColor);
\r
2255 InsertInPalette(whitePieceColor);
\r
2256 InsertInPalette(blackPieceColor);
\r
2257 InsertInPalette(highlightSquareColor);
\r
2258 InsertInPalette(premoveHighlightColor);
\r
2260 /* create a logical color palette according the information
\r
2261 * in the LOGPALETTE structure.
\r
2263 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2265 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2266 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2267 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2268 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2269 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2270 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2271 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2272 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2274 /* [AS] Force rendering of the font-based pieces */
\r
2275 if( fontBitmapSquareSize > 0 ) {
\r
2276 fontBitmapSquareSize = 0;
\r
2282 BoardWidth(int boardSize, int n)
\r
2283 { /* [HGM] argument n added to allow different width and height */
\r
2284 int lineGap = sizeInfo[boardSize].lineGap;
\r
2286 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2287 lineGap = appData.overrideLineGap;
\r
2290 return (n + 1) * lineGap +
\r
2291 n * sizeInfo[boardSize].squareSize;
\r
2294 /* Respond to board resize by dragging edge */
\r
2296 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2298 BoardSize newSize = NUM_SIZES - 1;
\r
2299 static int recurse = 0;
\r
2300 if (IsIconic(hwndMain)) return;
\r
2301 if (recurse > 0) return;
\r
2303 while (newSize > 0) {
\r
2304 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2305 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2306 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2309 boardSize = newSize;
\r
2310 InitDrawingSizes(boardSize, flags);
\r
2315 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2318 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2320 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2321 ChessSquare piece;
\r
2322 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2324 SIZE clockSize, messageSize;
\r
2326 char buf[MSG_SIZ];
\r
2328 HMENU hmenu = GetMenu(hwndMain);
\r
2329 RECT crect, wrect, oldRect;
\r
2331 LOGBRUSH logbrush;
\r
2332 VariantClass v = gameInfo.variant;
\r
2334 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2335 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2337 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2338 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2339 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2340 oldBoardSize = boardSize;
\r
2342 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2343 { // correct board size to one where built-in pieces exist
\r
2344 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2345 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2347 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2348 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2349 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2350 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2351 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2352 boardSize = SizeMiddling;
\r
2355 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2357 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2358 oldRect.top = wpMain.y;
\r
2359 oldRect.right = wpMain.x + wpMain.width;
\r
2360 oldRect.bottom = wpMain.y + wpMain.height;
\r
2362 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2363 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2364 squareSize = sizeInfo[boardSize].squareSize;
\r
2365 lineGap = sizeInfo[boardSize].lineGap;
\r
2366 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2367 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2369 // [HGM] decide on tininess based on total board width rather than square size
\r
2370 tinyLayout = squareSize * (BOARD_WIDTH);
\r
2371 tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0;
\r
2373 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2374 lineGap = appData.overrideLineGap;
\r
2377 if (tinyLayout != oldTinyLayout) {
\r
2378 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2379 if (tinyLayout == 2) {
\r
2380 style &= ~WS_SYSMENU;
\r
2381 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2382 "&Minimize\tCtrl+F4");
\r
2384 style |= WS_SYSMENU;
\r
2385 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2387 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2389 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2390 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2391 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2393 DrawMenuBar(hwndMain);
\r
2396 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2397 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2399 /* Get text area sizes */
\r
2400 hdc = GetDC(hwndMain);
\r
2401 if (appData.clockMode) {
\r
2402 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2404 snprintf(buf, MSG_SIZ, _("White"));
\r
2406 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2407 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2408 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2409 str = _("We only care about the height here");
\r
2410 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2411 SelectObject(hdc, oldFont);
\r
2412 ReleaseDC(hwndMain, hdc);
\r
2414 /* Compute where everything goes */
\r
2415 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2416 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2417 logoHeight = 2*clockSize.cy;
\r
2418 leftLogoRect.left = OUTER_MARGIN;
\r
2419 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2420 leftLogoRect.top = OUTER_MARGIN;
\r
2421 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2423 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2424 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2425 rightLogoRect.top = OUTER_MARGIN;
\r
2426 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2429 whiteRect.left = leftLogoRect.right;
\r
2430 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2431 whiteRect.top = OUTER_MARGIN;
\r
2432 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2434 blackRect.right = rightLogoRect.left;
\r
2435 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2436 blackRect.top = whiteRect.top;
\r
2437 blackRect.bottom = whiteRect.bottom;
\r
2439 whiteRect.left = OUTER_MARGIN;
\r
2440 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2441 whiteRect.top = OUTER_MARGIN;
\r
2442 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2444 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2445 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2446 blackRect.top = whiteRect.top;
\r
2447 blackRect.bottom = whiteRect.bottom;
\r
2449 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2452 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2453 if (appData.showButtonBar) {
\r
2454 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2455 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2457 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2459 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2460 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2462 boardRect.left = OUTER_MARGIN;
\r
2463 boardRect.right = boardRect.left + boardWidth;
\r
2464 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2465 boardRect.bottom = boardRect.top + boardHeight;
\r
2467 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2468 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2469 oldTinyLayout = tinyLayout;
\r
2470 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2471 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2472 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2473 winW *= 1 + twoBoards;
\r
2474 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2475 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2476 wpMain.height = winH; // without disturbing window attachments
\r
2477 GetWindowRect(hwndMain, &wrect);
\r
2478 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2479 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2481 // [HGM] placement: let attached windows follow size change.
\r
2482 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2483 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2484 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2485 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2486 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2488 /* compensate if menu bar wrapped */
\r
2489 GetClientRect(hwndMain, &crect);
\r
2490 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2491 wpMain.height += offby;
\r
2493 case WMSZ_TOPLEFT:
\r
2494 SetWindowPos(hwndMain, NULL,
\r
2495 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2496 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2499 case WMSZ_TOPRIGHT:
\r
2501 SetWindowPos(hwndMain, NULL,
\r
2502 wrect.left, wrect.bottom - wpMain.height,
\r
2503 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2506 case WMSZ_BOTTOMLEFT:
\r
2508 SetWindowPos(hwndMain, NULL,
\r
2509 wrect.right - wpMain.width, wrect.top,
\r
2510 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2513 case WMSZ_BOTTOMRIGHT:
\r
2517 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2518 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2523 for (i = 0; i < N_BUTTONS; i++) {
\r
2524 if (buttonDesc[i].hwnd != NULL) {
\r
2525 DestroyWindow(buttonDesc[i].hwnd);
\r
2526 buttonDesc[i].hwnd = NULL;
\r
2528 if (appData.showButtonBar) {
\r
2529 buttonDesc[i].hwnd =
\r
2530 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2531 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2532 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2533 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2534 (HMENU) buttonDesc[i].id,
\r
2535 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2536 if (tinyLayout == 2) {
\r
2537 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2538 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2539 MAKELPARAM(FALSE, 0));
\r
2541 if (buttonDesc[i].id == IDM_Pause)
\r
2542 hwndPause = buttonDesc[i].hwnd;
\r
2543 buttonDesc[i].wndproc = (WNDPROC)
\r
2544 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2547 if (gridPen != NULL) DeleteObject(gridPen);
\r
2548 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2549 if (premovePen != NULL) DeleteObject(premovePen);
\r
2550 if (lineGap != 0) {
\r
2551 logbrush.lbStyle = BS_SOLID;
\r
2552 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2554 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2555 lineGap, &logbrush, 0, NULL);
\r
2556 logbrush.lbColor = highlightSquareColor;
\r
2558 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2559 lineGap, &logbrush, 0, NULL);
\r
2561 logbrush.lbColor = premoveHighlightColor;
\r
2563 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2564 lineGap, &logbrush, 0, NULL);
\r
2566 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2567 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2568 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2569 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2570 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2571 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2572 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2573 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2575 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2576 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2577 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2578 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2579 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2580 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2581 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2582 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2586 /* [HGM] Licensing requirement */
\r
2588 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2591 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2593 GothicPopUp( "", VariantNormal);
\r
2596 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2598 /* Load piece bitmaps for this board size */
\r
2599 for (i=0; i<=2; i++) {
\r
2600 for (piece = WhitePawn;
\r
2601 (int) piece < (int) BlackPawn;
\r
2602 piece = (ChessSquare) ((int) piece + 1)) {
\r
2603 if (pieceBitmap[i][piece] != NULL)
\r
2604 DeleteObject(pieceBitmap[i][piece]);
\r
2605 pieceBitmap[i][piece] = NULL;
\r
2609 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2611 // Orthodox Chess pieces
\r
2612 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2613 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2614 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2615 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2616 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2617 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2618 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2619 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2620 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2621 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2622 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2623 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2624 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2625 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2626 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2627 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2628 // in Shogi, Hijack the unused Queen for Lance
\r
2629 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2633 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2634 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2635 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2638 if(squareSize <= 72 && squareSize >= 33) {
\r
2639 /* A & C are available in most sizes now */
\r
2640 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2641 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2642 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2643 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2647 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2648 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2649 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2650 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2653 } else { // Smirf-like
\r
2654 if(gameInfo.variant == VariantSChess) {
\r
2655 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2656 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2657 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2659 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2660 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2661 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2664 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2665 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2666 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2667 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2668 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2669 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2670 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2671 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2672 } else { // WinBoard standard
\r
2673 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2674 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2675 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2680 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2681 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2690 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2691 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2692 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2693 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2694 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2695 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2696 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2697 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2698 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2699 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2700 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2701 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2702 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2703 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2704 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2705 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2706 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2707 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2708 pieceBitmap[0][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2709 pieceBitmap[1][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2710 pieceBitmap[2][WhiteAmazon] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2711 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2712 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2713 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2714 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2715 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2716 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2718 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2719 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2720 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2721 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2722 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2723 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2724 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2725 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2726 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2727 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2728 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2729 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2730 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2732 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2733 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2734 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2735 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2736 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2737 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2738 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2739 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2740 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2741 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2742 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2743 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2746 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2747 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2748 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2749 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2750 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2751 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2752 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2753 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2754 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2755 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2756 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2757 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2758 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2759 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2760 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2764 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2765 /* special Shogi support in this size */
\r
2766 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2767 for (piece = WhitePawn;
\r
2768 (int) piece < (int) BlackPawn;
\r
2769 piece = (ChessSquare) ((int) piece + 1)) {
\r
2770 if (pieceBitmap[i][piece] != NULL)
\r
2771 DeleteObject(pieceBitmap[i][piece]);
\r
2774 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2775 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2776 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2777 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2778 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2779 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2780 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2781 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2782 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2783 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2784 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2785 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2786 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2787 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2788 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2789 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2790 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2791 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2792 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2793 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2794 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2795 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2796 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2797 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2798 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2799 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2800 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2801 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2802 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2803 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2804 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2805 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2806 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2807 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2808 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2809 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2810 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2811 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2812 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2813 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2814 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2815 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2819 if(appData.pieceDirectory[0]) for(i=WhitePawn; i<BlackPawn; i++) { // try for all missing pieces with new naming convention
\r
2820 char buf[MSG_SIZ];
\r
2821 if(pieceBitmap[0][i]) continue;
\r
2822 snprintf(buf, MSG_SIZ, "piece%d_", i);
\r
2823 pieceBitmap[0][i] = DoLoadBitmap(hInst, buf, squareSize, "s");
\r
2824 pieceBitmap[1][i] = DoLoadBitmap(hInst, buf, squareSize, "o");
\r
2825 pieceBitmap[2][i] = DoLoadBitmap(hInst, buf, squareSize, "w");
\r
2830 PieceBitmap(ChessSquare p, int kind)
\r
2832 if ((int) p >= (int) BlackPawn)
\r
2833 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2835 return pieceBitmap[kind][(int) p];
\r
2838 /***************************************************************/
\r
2840 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2841 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2843 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2844 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2848 SquareToPos(int row, int column, int * x, int * y)
\r
2851 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2852 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2854 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2855 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2860 DrawCoordsOnDC(HDC hdc)
\r
2862 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2863 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2864 char str[2] = { NULLCHAR, NULLCHAR };
\r
2865 int oldMode, oldAlign, x, y, start, i;
\r
2869 if (!appData.showCoords)
\r
2872 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2874 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2875 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2876 oldAlign = GetTextAlign(hdc);
\r
2877 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2879 y = boardRect.top + lineGap;
\r
2880 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2883 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2884 x += border - lineGap - 4; y += squareSize - 6;
\r
2886 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2887 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2888 str[0] = files[start + i];
\r
2889 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2890 y += squareSize + lineGap;
\r
2893 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2896 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2897 x += -border + 4; y += border - squareSize + 6;
\r
2899 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2900 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2901 str[0] = ranks[start + i];
\r
2902 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2903 x += squareSize + lineGap;
\r
2906 SelectObject(hdc, oldBrush);
\r
2907 SetBkMode(hdc, oldMode);
\r
2908 SetTextAlign(hdc, oldAlign);
\r
2909 SelectObject(hdc, oldFont);
\r
2913 DrawGridOnDC(HDC hdc)
\r
2917 if (lineGap != 0) {
\r
2918 oldPen = SelectObject(hdc, gridPen);
\r
2919 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2920 SelectObject(hdc, oldPen);
\r
2924 #define HIGHLIGHT_PEN 0
\r
2925 #define PREMOVE_PEN 1
\r
2928 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2931 HPEN oldPen, hPen;
\r
2932 if (lineGap == 0) return;
\r
2934 x1 = boardRect.left +
\r
2935 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2936 y1 = boardRect.top +
\r
2937 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2939 x1 = boardRect.left +
\r
2940 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2941 y1 = boardRect.top +
\r
2942 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2944 hPen = pen ? premovePen : highlightPen;
\r
2945 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2946 MoveToEx(hdc, x1, y1, NULL);
\r
2947 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2948 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2949 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2950 LineTo(hdc, x1, y1);
\r
2951 SelectObject(hdc, oldPen);
\r
2955 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2958 for (i=0; i<2; i++) {
\r
2959 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2960 DrawHighlightOnDC(hdc, TRUE,
\r
2961 h->sq[i].x, h->sq[i].y,
\r
2966 /* Note: sqcolor is used only in monoMode */
\r
2967 /* Note that this code is largely duplicated in woptions.c,
\r
2968 function DrawSampleSquare, so that needs to be updated too */
\r
2970 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2972 HBITMAP oldBitmap;
\r
2976 if (appData.blindfold) return;
\r
2978 /* [AS] Use font-based pieces if needed */
\r
2979 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2980 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2981 CreatePiecesFromFont();
\r
2983 if( fontBitmapSquareSize == squareSize ) {
\r
2984 int index = TranslatePieceToFontPiece(piece);
\r
2986 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2988 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2989 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2993 squareSize, squareSize,
\r
2998 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3000 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
3001 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
3005 squareSize, squareSize,
\r
3014 if (appData.monoMode) {
\r
3015 SelectObject(tmphdc, PieceBitmap(piece,
\r
3016 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3017 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3018 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3020 HBRUSH xBrush = whitePieceBrush;
\r
3021 tmpSize = squareSize;
\r
3022 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
3024 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3025 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3026 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3027 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3028 x += (squareSize - minorSize)>>1;
\r
3029 y += squareSize - minorSize - 2;
\r
3030 tmpSize = minorSize;
\r
3032 if (color || appData.allWhite ) {
\r
3033 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3035 oldBrush = SelectObject(hdc, xBrush);
\r
3036 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3037 if(appData.upsideDown && color==flipView)
\r
3038 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3040 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3041 /* Use black for outline of white pieces */
\r
3042 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3043 if(appData.upsideDown && color==flipView)
\r
3044 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3046 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3047 } else if(appData.pieceDirectory[0]) {
\r
3048 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3049 oldBrush = SelectObject(hdc, xBrush);
\r
3050 if(appData.upsideDown && color==flipView)
\r
3051 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3053 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3054 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3055 if(appData.upsideDown && color==flipView)
\r
3056 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3058 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3060 /* Use square color for details of black pieces */
\r
3061 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3062 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3063 if(appData.upsideDown && !flipView)
\r
3064 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3066 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3068 SelectObject(hdc, oldBrush);
\r
3069 SelectObject(tmphdc, oldBitmap);
\r
3073 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3074 int GetBackTextureMode( int algo )
\r
3076 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3080 case BACK_TEXTURE_MODE_PLAIN:
\r
3081 result = 1; /* Always use identity map */
\r
3083 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3084 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3092 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3093 to handle redraws cleanly (as random numbers would always be different).
\r
3095 VOID RebuildTextureSquareInfo()
\r
3105 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3107 if( liteBackTexture != NULL ) {
\r
3108 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3109 lite_w = bi.bmWidth;
\r
3110 lite_h = bi.bmHeight;
\r
3114 if( darkBackTexture != NULL ) {
\r
3115 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3116 dark_w = bi.bmWidth;
\r
3117 dark_h = bi.bmHeight;
\r
3121 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3122 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3123 if( (col + row) & 1 ) {
\r
3125 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3126 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3127 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3129 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3130 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3131 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3133 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3134 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3139 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3140 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3141 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3143 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3144 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3145 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3147 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3148 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3155 /* [AS] Arrow highlighting support */
\r
3157 static double A_WIDTH = 5; /* Width of arrow body */
\r
3159 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3160 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3162 static double Sqr( double x )
\r
3167 static int Round( double x )
\r
3169 return (int) (x + 0.5);
\r
3172 /* Draw an arrow between two points using current settings */
\r
3173 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3176 double dx, dy, j, k, x, y;
\r
3178 if( d_x == s_x ) {
\r
3179 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3181 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3184 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3185 arrow[1].y = d_y - h;
\r
3187 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3188 arrow[2].y = d_y - h;
\r
3193 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3194 arrow[5].y = d_y - h;
\r
3196 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3197 arrow[4].y = d_y - h;
\r
3199 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3202 else if( d_y == s_y ) {
\r
3203 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3206 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3208 arrow[1].x = d_x - w;
\r
3209 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3211 arrow[2].x = d_x - w;
\r
3212 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3217 arrow[5].x = d_x - w;
\r
3218 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3220 arrow[4].x = d_x - w;
\r
3221 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3224 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3227 /* [AS] Needed a lot of paper for this! :-) */
\r
3228 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3229 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3231 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3233 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3238 arrow[0].x = Round(x - j);
\r
3239 arrow[0].y = Round(y + j*dx);
\r
3241 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3242 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3245 x = (double) d_x - k;
\r
3246 y = (double) d_y - k*dy;
\r
3249 x = (double) d_x + k;
\r
3250 y = (double) d_y + k*dy;
\r
3253 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3255 arrow[6].x = Round(x - j);
\r
3256 arrow[6].y = Round(y + j*dx);
\r
3258 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3259 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3261 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3262 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3267 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3268 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3271 Polygon( hdc, arrow, 7 );
\r
3274 /* [AS] Draw an arrow between two squares */
\r
3275 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3277 int s_x, s_y, d_x, d_y;
\r
3284 if( s_col == d_col && s_row == d_row ) {
\r
3288 /* Get source and destination points */
\r
3289 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3290 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3293 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3295 else if( d_y < s_y ) {
\r
3296 d_y += squareSize / 2 + squareSize / 4;
\r
3299 d_y += squareSize / 2;
\r
3303 d_x += squareSize / 2 - squareSize / 4;
\r
3305 else if( d_x < s_x ) {
\r
3306 d_x += squareSize / 2 + squareSize / 4;
\r
3309 d_x += squareSize / 2;
\r
3312 s_x += squareSize / 2;
\r
3313 s_y += squareSize / 2;
\r
3315 /* Adjust width */
\r
3316 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3319 stLB.lbStyle = BS_SOLID;
\r
3320 stLB.lbColor = appData.highlightArrowColor;
\r
3323 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3324 holdpen = SelectObject( hdc, hpen );
\r
3325 hbrush = CreateBrushIndirect( &stLB );
\r
3326 holdbrush = SelectObject( hdc, hbrush );
\r
3328 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3330 SelectObject( hdc, holdpen );
\r
3331 SelectObject( hdc, holdbrush );
\r
3332 DeleteObject( hpen );
\r
3333 DeleteObject( hbrush );
\r
3336 BOOL HasHighlightInfo()
\r
3338 BOOL result = FALSE;
\r
3340 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3341 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3352 BOOL IsDrawArrowEnabled()
\r
3354 BOOL result = FALSE;
\r
3356 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3363 VOID DrawArrowHighlight( HDC hdc )
\r
3365 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3366 DrawArrowBetweenSquares( hdc,
\r
3367 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3368 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3372 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3374 HRGN result = NULL;
\r
3376 if( HasHighlightInfo() ) {
\r
3377 int x1, y1, x2, y2;
\r
3378 int sx, sy, dx, dy;
\r
3380 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3381 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3383 sx = MIN( x1, x2 );
\r
3384 sy = MIN( y1, y2 );
\r
3385 dx = MAX( x1, x2 ) + squareSize;
\r
3386 dy = MAX( y1, y2 ) + squareSize;
\r
3388 result = CreateRectRgn( sx, sy, dx, dy );
\r
3395 Warning: this function modifies the behavior of several other functions.
\r
3397 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3398 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3399 repaint is scattered all over the place, which is not good for features such as
\r
3400 "arrow highlighting" that require a full repaint of the board.
\r
3402 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3403 user interaction, when speed is not so important) but especially to avoid errors
\r
3404 in the displayed graphics.
\r
3406 In such patched places, I always try refer to this function so there is a single
\r
3407 place to maintain knowledge.
\r
3409 To restore the original behavior, just return FALSE unconditionally.
\r
3411 BOOL IsFullRepaintPreferrable()
\r
3413 BOOL result = FALSE;
\r
3415 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3416 /* Arrow may appear on the board */
\r
3424 This function is called by DrawPosition to know whether a full repaint must
\r
3427 Only DrawPosition may directly call this function, which makes use of
\r
3428 some state information. Other function should call DrawPosition specifying
\r
3429 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3431 BOOL DrawPositionNeedsFullRepaint()
\r
3433 BOOL result = FALSE;
\r
3436 Probably a slightly better policy would be to trigger a full repaint
\r
3437 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3438 but animation is fast enough that it's difficult to notice.
\r
3440 if( animInfo.piece == EmptySquare ) {
\r
3441 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3449 static HBITMAP borderBitmap;
\r
3452 DrawBackgroundOnDC(HDC hdc)
\r
3458 static char oldBorder[MSG_SIZ];
\r
3459 int w = 600, h = 600, mode;
\r
3461 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3462 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3463 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3465 if(borderBitmap == NULL) { // loading failed, use white
\r
3466 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3469 tmphdc = CreateCompatibleDC(hdc);
\r
3470 hbm = SelectObject(tmphdc, borderBitmap);
\r
3471 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3475 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3476 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3477 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3478 SetStretchBltMode(hdc, mode);
\r
3479 SelectObject(tmphdc, hbm);
\r
3484 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3486 int row, column, x, y, square_color, piece_color;
\r
3487 ChessSquare piece;
\r
3489 HDC texture_hdc = NULL;
\r
3491 /* [AS] Initialize background textures if needed */
\r
3492 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3493 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3494 if( backTextureSquareSize != squareSize
\r
3495 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3496 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3497 backTextureSquareSize = squareSize;
\r
3498 RebuildTextureSquareInfo();
\r
3501 texture_hdc = CreateCompatibleDC( hdc );
\r
3504 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3505 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3507 SquareToPos(row, column, &x, &y);
\r
3509 piece = board[row][column];
\r
3511 square_color = ((column + row) % 2) == 1;
\r
3512 if( gameInfo.variant == VariantXiangqi ) {
\r
3513 square_color = !InPalace(row, column);
\r
3514 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3515 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3517 piece_color = (int) piece < (int) BlackPawn;
\r
3520 /* [HGM] holdings file: light square or black */
\r
3521 if(column == BOARD_LEFT-2) {
\r
3522 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3525 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3529 if(column == BOARD_RGHT + 1 ) {
\r
3530 if( row < gameInfo.holdingsSize )
\r
3533 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3537 if(column == BOARD_LEFT-1 ) /* left align */
\r
3538 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3539 else if( column == BOARD_RGHT) /* right align */
\r
3540 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3541 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3543 if (appData.monoMode) {
\r
3544 if (piece == EmptySquare) {
\r
3545 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3546 square_color ? WHITENESS : BLACKNESS);
\r
3548 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3551 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3552 /* [AS] Draw the square using a texture bitmap */
\r
3553 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3554 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3555 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3558 squareSize, squareSize,
\r
3561 backTextureSquareInfo[r][c].mode,
\r
3562 backTextureSquareInfo[r][c].x,
\r
3563 backTextureSquareInfo[r][c].y );
\r
3565 SelectObject( texture_hdc, hbm );
\r
3567 if (piece != EmptySquare) {
\r
3568 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3572 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3574 oldBrush = SelectObject(hdc, brush );
\r
3575 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3576 SelectObject(hdc, oldBrush);
\r
3577 if (piece != EmptySquare)
\r
3578 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3583 if( texture_hdc != NULL ) {
\r
3584 DeleteDC( texture_hdc );
\r
3588 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3589 void fputDW(FILE *f, int x)
\r
3591 fputc(x & 255, f);
\r
3592 fputc(x>>8 & 255, f);
\r
3593 fputc(x>>16 & 255, f);
\r
3594 fputc(x>>24 & 255, f);
\r
3597 #define MAX_CLIPS 200 /* more than enough */
\r
3600 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3602 // HBITMAP bufferBitmap;
\r
3607 int w = 100, h = 50;
\r
3609 if(logo == NULL) {
\r
3610 if(!logoHeight) return;
\r
3611 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3613 // GetClientRect(hwndMain, &Rect);
\r
3614 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3615 // Rect.bottom-Rect.top+1);
\r
3616 tmphdc = CreateCompatibleDC(hdc);
\r
3617 hbm = SelectObject(tmphdc, logo);
\r
3618 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3622 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3623 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3624 SelectObject(tmphdc, hbm);
\r
3632 HDC hdc = GetDC(hwndMain);
\r
3633 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3634 if(appData.autoLogo) {
\r
3636 switch(gameMode) { // pick logos based on game mode
\r
3637 case IcsObserving:
\r
3638 whiteLogo = second.programLogo; // ICS logo
\r
3639 blackLogo = second.programLogo;
\r
3642 case IcsPlayingWhite:
\r
3643 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3644 blackLogo = second.programLogo; // ICS logo
\r
3646 case IcsPlayingBlack:
\r
3647 whiteLogo = second.programLogo; // ICS logo
\r
3648 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3650 case TwoMachinesPlay:
\r
3651 if(first.twoMachinesColor[0] == 'b') {
\r
3652 whiteLogo = second.programLogo;
\r
3653 blackLogo = first.programLogo;
\r
3656 case MachinePlaysWhite:
\r
3657 blackLogo = userLogo;
\r
3659 case MachinePlaysBlack:
\r
3660 whiteLogo = userLogo;
\r
3661 blackLogo = first.programLogo;
\r
3664 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3665 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3666 ReleaseDC(hwndMain, hdc);
\r
3671 UpdateLogos(int display)
\r
3672 { // called after loading new engine(s), in tourney or from menu
\r
3673 LoadLogo(&first, 0, FALSE);
\r
3674 LoadLogo(&second, 1, appData.icsActive);
\r
3675 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3676 if(display) DisplayLogos();
\r
3679 static HDC hdcSeek;
\r
3681 // [HGM] seekgraph
\r
3682 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3685 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3686 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3687 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3688 SelectObject( hdcSeek, hp );
\r
3691 // front-end wrapper for drawing functions to do rectangles
\r
3692 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3697 if (hdcSeek == NULL) {
\r
3698 hdcSeek = GetDC(hwndMain);
\r
3699 if (!appData.monoMode) {
\r
3700 SelectPalette(hdcSeek, hPal, FALSE);
\r
3701 RealizePalette(hdcSeek);
\r
3704 hp = SelectObject( hdcSeek, gridPen );
\r
3705 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3706 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3707 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3708 SelectObject( hdcSeek, hp );
\r
3711 // front-end wrapper for putting text in graph
\r
3712 void DrawSeekText(char *buf, int x, int y)
\r
3715 SetBkMode( hdcSeek, TRANSPARENT );
\r
3716 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3717 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3720 void DrawSeekDot(int x, int y, int color)
\r
3722 int square = color & 0x80;
\r
3723 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3724 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3727 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3728 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3730 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3731 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3732 SelectObject(hdcSeek, oldBrush);
\r
3735 void DrawSeekOpen()
\r
3739 void DrawSeekClose()
\r
3744 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3746 static Board lastReq[2], lastDrawn[2];
\r
3747 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3748 static int lastDrawnFlipView = 0;
\r
3749 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3750 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3753 HBITMAP bufferBitmap;
\r
3754 HBITMAP oldBitmap;
\r
3756 HRGN clips[MAX_CLIPS];
\r
3757 ChessSquare dragged_piece = EmptySquare;
\r
3758 int nr = twoBoards*partnerUp;
\r
3760 /* I'm undecided on this - this function figures out whether a full
\r
3761 * repaint is necessary on its own, so there's no real reason to have the
\r
3762 * caller tell it that. I think this can safely be set to FALSE - but
\r
3763 * if we trust the callers not to request full repaints unnessesarily, then
\r
3764 * we could skip some clipping work. In other words, only request a full
\r
3765 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3766 * gamestart and similar) --Hawk
\r
3768 Boolean fullrepaint = repaint;
\r
3770 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3772 if( DrawPositionNeedsFullRepaint() ) {
\r
3773 fullrepaint = TRUE;
\r
3776 if (board == NULL) {
\r
3777 if (!lastReqValid[nr]) {
\r
3780 board = lastReq[nr];
\r
3782 CopyBoard(lastReq[nr], board);
\r
3783 lastReqValid[nr] = 1;
\r
3786 if (doingSizing) {
\r
3790 if (IsIconic(hwndMain)) {
\r
3794 if (hdc == NULL) {
\r
3795 hdc = GetDC(hwndMain);
\r
3796 if (!appData.monoMode) {
\r
3797 SelectPalette(hdc, hPal, FALSE);
\r
3798 RealizePalette(hdc);
\r
3802 releaseDC = FALSE;
\r
3805 /* Create some work-DCs */
\r
3806 hdcmem = CreateCompatibleDC(hdc);
\r
3807 tmphdc = CreateCompatibleDC(hdc);
\r
3809 /* If dragging is in progress, we temporarely remove the piece */
\r
3810 /* [HGM] or temporarily decrease count if stacked */
\r
3811 /* !! Moved to before board compare !! */
\r
3812 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3813 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3814 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3815 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3816 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3818 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3819 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3820 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3822 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3825 /* Figure out which squares need updating by comparing the
\r
3826 * newest board with the last drawn board and checking if
\r
3827 * flipping has changed.
\r
3829 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3830 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3831 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3832 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3833 SquareToPos(row, column, &x, &y);
\r
3834 clips[num_clips++] =
\r
3835 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3839 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3840 for (i=0; i<2; i++) {
\r
3841 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3842 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3843 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3844 lastDrawnHighlight.sq[i].y >= 0) {
\r
3845 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3846 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3847 clips[num_clips++] =
\r
3848 CreateRectRgn(x - lineGap, y - lineGap,
\r
3849 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3851 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3852 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3853 clips[num_clips++] =
\r
3854 CreateRectRgn(x - lineGap, y - lineGap,
\r
3855 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3859 for (i=0; i<2; i++) {
\r
3860 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3861 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3862 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3863 lastDrawnPremove.sq[i].y >= 0) {
\r
3864 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3865 lastDrawnPremove.sq[i].x, &x, &y);
\r
3866 clips[num_clips++] =
\r
3867 CreateRectRgn(x - lineGap, y - lineGap,
\r
3868 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3870 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3871 premoveHighlightInfo.sq[i].y >= 0) {
\r
3872 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3873 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3874 clips[num_clips++] =
\r
3875 CreateRectRgn(x - lineGap, y - lineGap,
\r
3876 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3880 } else { // nr == 1
\r
3881 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3882 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3883 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3884 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3885 for (i=0; i<2; i++) {
\r
3886 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3887 partnerHighlightInfo.sq[i].y >= 0) {
\r
3888 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3889 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3890 clips[num_clips++] =
\r
3891 CreateRectRgn(x - lineGap, y - lineGap,
\r
3892 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3894 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3895 oldPartnerHighlight.sq[i].y >= 0) {
\r
3896 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3897 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3898 clips[num_clips++] =
\r
3899 CreateRectRgn(x - lineGap, y - lineGap,
\r
3900 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3905 fullrepaint = TRUE;
\r
3908 /* Create a buffer bitmap - this is the actual bitmap
\r
3909 * being written to. When all the work is done, we can
\r
3910 * copy it to the real DC (the screen). This avoids
\r
3911 * the problems with flickering.
\r
3913 GetClientRect(hwndMain, &Rect);
\r
3914 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3915 Rect.bottom-Rect.top+1);
\r
3916 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3917 if (!appData.monoMode) {
\r
3918 SelectPalette(hdcmem, hPal, FALSE);
\r
3921 /* Create clips for dragging */
\r
3922 if (!fullrepaint) {
\r
3923 if (dragInfo.from.x >= 0) {
\r
3924 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3925 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3927 if (dragInfo.start.x >= 0) {
\r
3928 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3929 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3931 if (dragInfo.pos.x >= 0) {
\r
3932 x = dragInfo.pos.x - squareSize / 2;
\r
3933 y = dragInfo.pos.y - squareSize / 2;
\r
3934 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3936 if (dragInfo.lastpos.x >= 0) {
\r
3937 x = dragInfo.lastpos.x - squareSize / 2;
\r
3938 y = dragInfo.lastpos.y - squareSize / 2;
\r
3939 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3943 /* Are we animating a move?
\r
3945 * - remove the piece from the board (temporarely)
\r
3946 * - calculate the clipping region
\r
3948 if (!fullrepaint) {
\r
3949 if (animInfo.piece != EmptySquare) {
\r
3950 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3951 x = boardRect.left + animInfo.lastpos.x;
\r
3952 y = boardRect.top + animInfo.lastpos.y;
\r
3953 x2 = boardRect.left + animInfo.pos.x;
\r
3954 y2 = boardRect.top + animInfo.pos.y;
\r
3955 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3956 /* Slight kludge. The real problem is that after AnimateMove is
\r
3957 done, the position on the screen does not match lastDrawn.
\r
3958 This currently causes trouble only on e.p. captures in
\r
3959 atomic, where the piece moves to an empty square and then
\r
3960 explodes. The old and new positions both had an empty square
\r
3961 at the destination, but animation has drawn a piece there and
\r
3962 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3963 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3967 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3968 if (num_clips == 0)
\r
3969 fullrepaint = TRUE;
\r
3971 /* Set clipping on the memory DC */
\r
3972 if (!fullrepaint) {
\r
3973 SelectClipRgn(hdcmem, clips[0]);
\r
3974 for (x = 1; x < num_clips; x++) {
\r
3975 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3976 abort(); // this should never ever happen!
\r
3980 /* Do all the drawing to the memory DC */
\r
3981 if(explodeInfo.radius) { // [HGM] atomic
\r
3983 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3984 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3985 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3986 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3987 x += squareSize/2;
\r
3988 y += squareSize/2;
\r
3989 if(!fullrepaint) {
\r
3990 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3991 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3993 DrawGridOnDC(hdcmem);
\r
3994 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3995 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3996 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3997 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3998 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3999 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4000 SelectObject(hdcmem, oldBrush);
\r
4002 if(border) DrawBackgroundOnDC(hdcmem);
\r
4003 DrawGridOnDC(hdcmem);
\r
4004 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
4005 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
4006 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
4008 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
4009 oldPartnerHighlight = partnerHighlightInfo;
\r
4011 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4013 if(nr == 0) // [HGM] dual: markers only on left board
\r
4014 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4015 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4016 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
4017 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
4018 SquareToPos(row, column, &x, &y);
\r
4019 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
4020 x + 3*squareSize/4, y + 3*squareSize/4);
\r
4021 SelectObject(hdcmem, oldBrush);
\r
4026 if( appData.highlightMoveWithArrow ) {
\r
4028 DrawArrowHighlight(hdcmem);
\r
4031 DrawCoordsOnDC(hdcmem);
\r
4033 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4034 /* to make sure lastDrawn contains what is actually drawn */
\r
4036 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4037 if (dragged_piece != EmptySquare) {
\r
4038 /* [HGM] or restack */
\r
4039 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4040 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4042 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4043 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4045 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4046 x = dragInfo.pos.x - squareSize / 2;
\r
4047 y = dragInfo.pos.y - squareSize / 2;
\r
4048 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4049 ((int) dragInfo.piece < (int) BlackPawn),
\r
4050 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4053 /* Put the animated piece back into place and draw it */
\r
4054 if (animInfo.piece != EmptySquare) {
\r
4055 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4056 x = boardRect.left + animInfo.pos.x;
\r
4057 y = boardRect.top + animInfo.pos.y;
\r
4058 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4059 ((int) animInfo.piece < (int) BlackPawn),
\r
4060 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4063 /* Release the bufferBitmap by selecting in the old bitmap
\r
4064 * and delete the memory DC
\r
4066 SelectObject(hdcmem, oldBitmap);
\r
4069 /* Set clipping on the target DC */
\r
4070 if (!fullrepaint) {
\r
4071 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4073 GetRgnBox(clips[x], &rect);
\r
4074 DeleteObject(clips[x]);
\r
4075 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4076 rect.right + wpMain.width/2, rect.bottom);
\r
4078 SelectClipRgn(hdc, clips[0]);
\r
4079 for (x = 1; x < num_clips; x++) {
\r
4080 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4081 abort(); // this should never ever happen!
\r
4085 /* Copy the new bitmap onto the screen in one go.
\r
4086 * This way we avoid any flickering
\r
4088 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4089 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4090 boardRect.right - boardRect.left,
\r
4091 boardRect.bottom - boardRect.top,
\r
4092 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4093 if(saveDiagFlag) {
\r
4094 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4095 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4097 GetObject(bufferBitmap, sizeof(b), &b);
\r
4098 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4099 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4100 bih.biWidth = b.bmWidth;
\r
4101 bih.biHeight = b.bmHeight;
\r
4103 bih.biBitCount = b.bmBitsPixel;
\r
4104 bih.biCompression = 0;
\r
4105 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4106 bih.biXPelsPerMeter = 0;
\r
4107 bih.biYPelsPerMeter = 0;
\r
4108 bih.biClrUsed = 0;
\r
4109 bih.biClrImportant = 0;
\r
4110 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4111 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4112 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4113 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4115 wb = b.bmWidthBytes;
\r
4117 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4118 int k = ((int*) pData)[i];
\r
4119 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4120 if(j >= 16) break;
\r
4122 if(j >= nrColors) nrColors = j+1;
\r
4124 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4126 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4127 for(w=0; w<(wb>>2); w+=2) {
\r
4128 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4129 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4130 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4131 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4132 pData[p++] = m | j<<4;
\r
4134 while(p&3) pData[p++] = 0;
\r
4137 wb = ((wb+31)>>5)<<2;
\r
4139 // write BITMAPFILEHEADER
\r
4140 fprintf(diagFile, "BM");
\r
4141 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4142 fputDW(diagFile, 0);
\r
4143 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4144 // write BITMAPINFOHEADER
\r
4145 fputDW(diagFile, 40);
\r
4146 fputDW(diagFile, b.bmWidth);
\r
4147 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4148 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4149 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4150 fputDW(diagFile, 0);
\r
4151 fputDW(diagFile, 0);
\r
4152 fputDW(diagFile, 0);
\r
4153 fputDW(diagFile, 0);
\r
4154 fputDW(diagFile, 0);
\r
4155 fputDW(diagFile, 0);
\r
4156 // write color table
\r
4158 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4159 // write bitmap data
\r
4160 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4161 fputc(pData[i], diagFile);
\r
4166 SelectObject(tmphdc, oldBitmap);
\r
4168 /* Massive cleanup */
\r
4169 for (x = 0; x < num_clips; x++)
\r
4170 DeleteObject(clips[x]);
\r
4173 DeleteObject(bufferBitmap);
\r
4176 ReleaseDC(hwndMain, hdc);
\r
4178 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4180 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4182 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4185 /* CopyBoard(lastDrawn, board);*/
\r
4186 lastDrawnHighlight = highlightInfo;
\r
4187 lastDrawnPremove = premoveHighlightInfo;
\r
4188 lastDrawnFlipView = flipView;
\r
4189 lastDrawnValid[nr] = 1;
\r
4192 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4197 saveDiagFlag = 1; diagFile = f;
\r
4198 HDCDrawPosition(NULL, TRUE, NULL);
\r
4206 /*---------------------------------------------------------------------------*\
\r
4207 | CLIENT PAINT PROCEDURE
\r
4208 | This is the main event-handler for the WM_PAINT message.
\r
4210 \*---------------------------------------------------------------------------*/
\r
4212 PaintProc(HWND hwnd)
\r
4218 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4219 if (IsIconic(hwnd)) {
\r
4220 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4222 if (!appData.monoMode) {
\r
4223 SelectPalette(hdc, hPal, FALSE);
\r
4224 RealizePalette(hdc);
\r
4226 HDCDrawPosition(hdc, 1, NULL);
\r
4227 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4228 flipView = !flipView; partnerUp = !partnerUp;
\r
4229 HDCDrawPosition(hdc, 1, NULL);
\r
4230 flipView = !flipView; partnerUp = !partnerUp;
\r
4233 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4234 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4235 ETO_CLIPPED|ETO_OPAQUE,
\r
4236 &messageRect, messageText, strlen(messageText), NULL);
\r
4237 SelectObject(hdc, oldFont);
\r
4238 DisplayBothClocks();
\r
4241 EndPaint(hwnd,&ps);
\r
4249 * If the user selects on a border boundary, return -1; if off the board,
\r
4250 * return -2. Otherwise map the event coordinate to the square.
\r
4251 * The offset boardRect.left or boardRect.top must already have been
\r
4252 * subtracted from x.
\r
4254 int EventToSquare(x, limit)
\r
4259 if (x < lineGap + border)
\r
4261 x -= lineGap + border;
\r
4262 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4264 x /= (squareSize + lineGap);
\r
4276 DropEnable dropEnables[] = {
\r
4277 { 'P', DP_Pawn, N_("Pawn") },
\r
4278 { 'N', DP_Knight, N_("Knight") },
\r
4279 { 'B', DP_Bishop, N_("Bishop") },
\r
4280 { 'R', DP_Rook, N_("Rook") },
\r
4281 { 'Q', DP_Queen, N_("Queen") },
\r
4285 SetupDropMenu(HMENU hmenu)
\r
4287 int i, count, enable;
\r
4289 extern char white_holding[], black_holding[];
\r
4290 char item[MSG_SIZ];
\r
4292 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4293 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4294 dropEnables[i].piece);
\r
4296 while (p && *p++ == dropEnables[i].piece) count++;
\r
4297 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4298 enable = count > 0 || !appData.testLegality
\r
4299 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4300 && !appData.icsActive);
\r
4301 ModifyMenu(hmenu, dropEnables[i].command,
\r
4302 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4303 dropEnables[i].command, item);
\r
4307 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4309 dragInfo.lastpos.x = boardRect.left + x;
\r
4310 dragInfo.lastpos.y = boardRect.top + y;
\r
4311 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4312 dragInfo.from.x = fromX;
\r
4313 dragInfo.from.y = fromY;
\r
4314 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4315 dragInfo.start = dragInfo.from;
\r
4316 SetCapture(hwndMain);
\r
4319 void DragPieceEnd(int x, int y)
\r
4322 dragInfo.start.x = dragInfo.start.y = -1;
\r
4323 dragInfo.from = dragInfo.start;
\r
4324 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4327 void ChangeDragPiece(ChessSquare piece)
\r
4329 dragInfo.piece = piece;
\r
4332 /* Event handler for mouse messages */
\r
4334 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4338 static int recursive = 0;
\r
4340 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4343 if (message == WM_MBUTTONUP) {
\r
4344 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4345 to the middle button: we simulate pressing the left button too!
\r
4347 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4348 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4354 pt.x = LOWORD(lParam);
\r
4355 pt.y = HIWORD(lParam);
\r
4356 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4357 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4358 if (!flipView && y >= 0) {
\r
4359 y = BOARD_HEIGHT - 1 - y;
\r
4361 if (flipView && x >= 0) {
\r
4362 x = BOARD_WIDTH - 1 - x;
\r
4365 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4366 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4368 switch (message) {
\r
4369 case WM_LBUTTONDOWN:
\r
4370 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4371 ClockClick(flipClock); break;
\r
4372 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4373 ClockClick(!flipClock); break;
\r
4375 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4376 dragInfo.start.x = dragInfo.start.y = -1;
\r
4377 dragInfo.from = dragInfo.start;
\r
4379 if(fromX == -1 && frozen) { // not sure where this is for
\r
4380 fromX = fromY = -1;
\r
4381 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4384 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4385 DrawPosition(TRUE, NULL);
\r
4388 case WM_LBUTTONUP:
\r
4389 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4390 DrawPosition(TRUE, NULL);
\r
4393 case WM_MOUSEMOVE:
\r
4394 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4395 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4396 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4397 if ((appData.animateDragging || appData.highlightDragging)
\r
4398 && (wParam & MK_LBUTTON || dragging == 2)
\r
4399 && dragInfo.from.x >= 0)
\r
4401 BOOL full_repaint = FALSE;
\r
4403 if (appData.animateDragging) {
\r
4404 dragInfo.pos = pt;
\r
4406 if (appData.highlightDragging) {
\r
4407 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4408 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4409 full_repaint = TRUE;
\r
4413 DrawPosition( full_repaint, NULL);
\r
4415 dragInfo.lastpos = dragInfo.pos;
\r
4419 case WM_MOUSEWHEEL: // [DM]
\r
4420 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4421 /* Mouse Wheel is being rolled forward
\r
4422 * Play moves forward
\r
4424 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4425 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4426 /* Mouse Wheel is being rolled backward
\r
4427 * Play moves backward
\r
4429 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4430 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4434 case WM_MBUTTONUP:
\r
4435 case WM_RBUTTONUP:
\r
4437 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4440 case WM_MBUTTONDOWN:
\r
4441 case WM_RBUTTONDOWN:
\r
4444 fromX = fromY = -1;
\r
4445 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4446 dragInfo.start.x = dragInfo.start.y = -1;
\r
4447 dragInfo.from = dragInfo.start;
\r
4448 dragInfo.lastpos = dragInfo.pos;
\r
4449 if (appData.highlightDragging) {
\r
4450 ClearHighlights();
\r
4453 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4454 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4455 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4456 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4457 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4461 DrawPosition(TRUE, NULL);
\r
4463 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4466 if (message == WM_MBUTTONDOWN) {
\r
4467 buttonCount = 3; /* even if system didn't think so */
\r
4468 if (wParam & MK_SHIFT)
\r
4469 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4471 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4472 } else { /* message == WM_RBUTTONDOWN */
\r
4473 /* Just have one menu, on the right button. Windows users don't
\r
4474 think to try the middle one, and sometimes other software steals
\r
4475 it, or it doesn't really exist. */
\r
4476 if(gameInfo.variant != VariantShogi)
\r
4477 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4479 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4483 SetCapture(hwndMain);
\r
4486 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4487 SetupDropMenu(hmenu);
\r
4488 MenuPopup(hwnd, pt, hmenu, -1);
\r
4498 /* Preprocess messages for buttons in main window */
\r
4500 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4502 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4505 for (i=0; i<N_BUTTONS; i++) {
\r
4506 if (buttonDesc[i].id == id) break;
\r
4508 if (i == N_BUTTONS) return 0;
\r
4509 switch (message) {
\r
4514 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4515 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4522 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4525 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4526 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4527 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4528 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4530 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4532 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4533 TypeInEvent((char)wParam);
\r
4539 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4542 static int promoStyle;
\r
4544 /* Process messages for Promotion dialog box */
\r
4546 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4551 switch (message) {
\r
4553 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4554 /* Center the dialog over the application window */
\r
4555 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4556 Translate(hDlg, DLG_PromotionKing);
\r
4557 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4558 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4559 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4560 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4561 SW_SHOW : SW_HIDE);
\r
4562 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4563 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4564 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4565 PieceToChar(WhiteAngel) != '~') ||
\r
4566 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4567 PieceToChar(BlackAngel) != '~') ) ?
\r
4568 SW_SHOW : SW_HIDE);
\r
4569 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4570 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4571 PieceToChar(WhiteMarshall) != '~') ||
\r
4572 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4573 PieceToChar(BlackMarshall) != '~') ) ?
\r
4574 SW_SHOW : SW_HIDE);
\r
4575 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4576 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4577 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4579 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4580 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4581 SetWindowText(hDlg, "Promote?");
\r
4583 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4584 gameInfo.variant == VariantSuper ?
\r
4585 SW_SHOW : SW_HIDE);
\r
4588 case WM_COMMAND: /* message: received a command */
\r
4589 switch (LOWORD(wParam)) {
\r
4591 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4592 ClearHighlights();
\r
4593 DrawPosition(FALSE, NULL);
\r
4596 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4599 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4602 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4603 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4606 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4607 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4609 case PB_Chancellor:
\r
4610 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4612 case PB_Archbishop:
\r
4613 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4616 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4617 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4622 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4623 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4624 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4625 fromX = fromY = -1;
\r
4626 if (!appData.highlightLastMove) {
\r
4627 ClearHighlights();
\r
4628 DrawPosition(FALSE, NULL);
\r
4635 /* Pop up promotion dialog */
\r
4637 PromotionPopup(HWND hwnd)
\r
4641 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4642 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4643 hwnd, (DLGPROC)lpProc);
\r
4644 FreeProcInstance(lpProc);
\r
4648 PromotionPopUp(char choice)
\r
4650 promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));
\r
4651 DrawPosition(TRUE, NULL);
\r
4652 PromotionPopup(hwndMain);
\r
4656 LoadGameDialog(HWND hwnd, char* title)
\r
4660 char fileTitle[MSG_SIZ];
\r
4661 f = OpenFileDialog(hwnd, "rb", "",
\r
4662 appData.oldSaveStyle ? "gam" : "pgn",
\r
4664 title, &number, fileTitle, NULL);
\r
4666 cmailMsgLoaded = FALSE;
\r
4667 if (number == 0) {
\r
4668 int error = GameListBuild(f);
\r
4670 DisplayError(_("Cannot build game list"), error);
\r
4671 } else if (!ListEmpty(&gameList) &&
\r
4672 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4673 GameListPopUp(f, fileTitle);
\r
4676 GameListDestroy();
\r
4679 LoadGame(f, number, fileTitle, FALSE);
\r
4683 int get_term_width()
\r
4688 HFONT hfont, hold_font;
\r
4693 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4697 // get the text metrics
\r
4698 hdc = GetDC(hText);
\r
4699 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4700 if (consoleCF.dwEffects & CFE_BOLD)
\r
4701 lf.lfWeight = FW_BOLD;
\r
4702 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4703 lf.lfItalic = TRUE;
\r
4704 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4705 lf.lfStrikeOut = TRUE;
\r
4706 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4707 lf.lfUnderline = TRUE;
\r
4708 hfont = CreateFontIndirect(&lf);
\r
4709 hold_font = SelectObject(hdc, hfont);
\r
4710 GetTextMetrics(hdc, &tm);
\r
4711 SelectObject(hdc, hold_font);
\r
4712 DeleteObject(hfont);
\r
4713 ReleaseDC(hText, hdc);
\r
4715 // get the rectangle
\r
4716 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4718 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4721 void UpdateICSWidth(HWND hText)
\r
4723 LONG old_width, new_width;
\r
4725 new_width = get_term_width(hText, FALSE);
\r
4726 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4727 if (new_width != old_width)
\r
4729 ics_update_width(new_width);
\r
4730 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4735 ChangedConsoleFont()
\r
4738 CHARRANGE tmpsel, sel;
\r
4739 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4740 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4741 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4744 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4745 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4746 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4747 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4748 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4749 * size. This was undocumented in the version of MSVC++ that I had
\r
4750 * when I wrote the code, but is apparently documented now.
\r
4752 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4753 cfmt.bCharSet = f->lf.lfCharSet;
\r
4754 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4755 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4756 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4757 /* Why are the following seemingly needed too? */
\r
4758 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4759 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4760 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4762 tmpsel.cpMax = -1; /*999999?*/
\r
4763 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4764 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4765 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4766 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4768 paraf.cbSize = sizeof(paraf);
\r
4769 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4770 paraf.dxStartIndent = 0;
\r
4771 paraf.dxOffset = WRAP_INDENT;
\r
4772 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4773 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4774 UpdateICSWidth(hText);
\r
4777 /*---------------------------------------------------------------------------*\
\r
4779 * Window Proc for main window
\r
4781 \*---------------------------------------------------------------------------*/
\r
4783 /* Process messages for main window, etc. */
\r
4785 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4792 char fileTitle[MSG_SIZ];
\r
4793 static SnapData sd;
\r
4794 static int peek=0;
\r
4796 switch (message) {
\r
4798 case WM_PAINT: /* message: repaint portion of window */
\r
4802 case WM_ERASEBKGND:
\r
4803 if (IsIconic(hwnd)) {
\r
4804 /* Cheat; change the message */
\r
4805 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4807 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4811 case WM_LBUTTONDOWN:
\r
4812 case WM_MBUTTONDOWN:
\r
4813 case WM_RBUTTONDOWN:
\r
4814 case WM_LBUTTONUP:
\r
4815 case WM_MBUTTONUP:
\r
4816 case WM_RBUTTONUP:
\r
4817 case WM_MOUSEMOVE:
\r
4818 case WM_MOUSEWHEEL:
\r
4819 MouseEvent(hwnd, message, wParam, lParam);
\r
4823 if((char)wParam == '\b') {
\r
4824 ForwardEvent(); peek = 0;
\r
4827 JAWS_KBUP_NAVIGATION
\r
4832 if((char)wParam == '\b') {
\r
4833 if(!peek) BackwardEvent(), peek = 1;
\r
4836 JAWS_KBDOWN_NAVIGATION
\r
4842 JAWS_ALT_INTERCEPT
\r
4844 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4845 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4846 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4847 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4849 SendMessage(h, message, wParam, lParam);
\r
4850 } else if(lParam != KF_REPEAT) {
\r
4851 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4852 TypeInEvent((char)wParam);
\r
4853 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4854 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4859 case WM_PALETTECHANGED:
\r
4860 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4862 HDC hdc = GetDC(hwndMain);
\r
4863 SelectPalette(hdc, hPal, TRUE);
\r
4864 nnew = RealizePalette(hdc);
\r
4866 paletteChanged = TRUE;
\r
4868 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4870 ReleaseDC(hwnd, hdc);
\r
4874 case WM_QUERYNEWPALETTE:
\r
4875 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4877 HDC hdc = GetDC(hwndMain);
\r
4878 paletteChanged = FALSE;
\r
4879 SelectPalette(hdc, hPal, FALSE);
\r
4880 nnew = RealizePalette(hdc);
\r
4882 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4884 ReleaseDC(hwnd, hdc);
\r
4889 case WM_COMMAND: /* message: command from application menu */
\r
4890 wmId = LOWORD(wParam);
\r
4895 SAY("new game enter a move to play against the computer with white");
\r
4898 case IDM_NewGameFRC:
\r
4899 if( NewGameFRC() == 0 ) {
\r
4904 case IDM_NewVariant:
\r
4905 NewVariantPopup(hwnd);
\r
4908 case IDM_LoadGame:
\r
4909 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4912 case IDM_LoadNextGame:
\r
4916 case IDM_LoadPrevGame:
\r
4920 case IDM_ReloadGame:
\r
4924 case IDM_LoadPosition:
\r
4925 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4926 Reset(FALSE, TRUE);
\r
4929 f = OpenFileDialog(hwnd, "rb", "",
\r
4930 appData.oldSaveStyle ? "pos" : "fen",
\r
4932 _("Load Position from File"), &number, fileTitle, NULL);
\r
4934 LoadPosition(f, number, fileTitle);
\r
4938 case IDM_LoadNextPosition:
\r
4939 ReloadPosition(1);
\r
4942 case IDM_LoadPrevPosition:
\r
4943 ReloadPosition(-1);
\r
4946 case IDM_ReloadPosition:
\r
4947 ReloadPosition(0);
\r
4950 case IDM_SaveGame:
\r
4951 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4952 f = OpenFileDialog(hwnd, "a", defName,
\r
4953 appData.oldSaveStyle ? "gam" : "pgn",
\r
4955 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4957 SaveGame(f, 0, "");
\r
4961 case IDM_SavePosition:
\r
4962 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4963 f = OpenFileDialog(hwnd, "a", defName,
\r
4964 appData.oldSaveStyle ? "pos" : "fen",
\r
4966 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4968 SavePosition(f, 0, "");
\r
4972 case IDM_SaveDiagram:
\r
4973 defName = "diagram";
\r
4974 f = OpenFileDialog(hwnd, "wb", defName,
\r
4977 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4983 case IDM_SaveSelected:
\r
4984 f = OpenFileDialog(hwnd, "a", "",
\r
4987 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4989 SaveSelected(f, 0, "");
\r
4993 case IDM_CreateBook:
\r
4994 CreateBookEvent();
\r
4997 case IDM_CopyGame:
\r
4998 CopyGameToClipboard();
\r
5001 case IDM_PasteGame:
\r
5002 PasteGameFromClipboard();
\r
5005 case IDM_CopyGameListToClipboard:
\r
5006 CopyGameListToClipboard();
\r
5009 /* [AS] Autodetect FEN or PGN data */
\r
5010 case IDM_PasteAny:
\r
5011 PasteGameOrFENFromClipboard();
\r
5014 /* [AS] Move history */
\r
5015 case IDM_ShowMoveHistory:
\r
5016 if( MoveHistoryIsUp() ) {
\r
5017 MoveHistoryPopDown();
\r
5020 MoveHistoryPopUp();
\r
5024 /* [AS] Eval graph */
\r
5025 case IDM_ShowEvalGraph:
\r
5026 if( EvalGraphIsUp() ) {
\r
5027 EvalGraphPopDown();
\r
5031 SetFocus(hwndMain);
\r
5035 /* [AS] Engine output */
\r
5036 case IDM_ShowEngineOutput:
\r
5037 if( EngineOutputIsUp() ) {
\r
5038 EngineOutputPopDown();
\r
5041 EngineOutputPopUp();
\r
5045 /* [AS] User adjudication */
\r
5046 case IDM_UserAdjudication_White:
\r
5047 UserAdjudicationEvent( +1 );
\r
5050 case IDM_UserAdjudication_Black:
\r
5051 UserAdjudicationEvent( -1 );
\r
5054 case IDM_UserAdjudication_Draw:
\r
5055 UserAdjudicationEvent( 0 );
\r
5058 /* [AS] Game list options dialog */
\r
5059 case IDM_GameListOptions:
\r
5060 GameListOptions();
\r
5067 case IDM_CopyPosition:
\r
5068 CopyFENToClipboard();
\r
5071 case IDM_PastePosition:
\r
5072 PasteFENFromClipboard();
\r
5075 case IDM_MailMove:
\r
5079 case IDM_ReloadCMailMsg:
\r
5080 Reset(TRUE, TRUE);
\r
5081 ReloadCmailMsgEvent(FALSE);
\r
5084 case IDM_Minimize:
\r
5085 ShowWindow(hwnd, SW_MINIMIZE);
\r
5092 case IDM_MachineWhite:
\r
5093 MachineWhiteEvent();
\r
5095 * refresh the tags dialog only if it's visible
\r
5097 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5099 tags = PGNTags(&gameInfo);
\r
5100 TagsPopUp(tags, CmailMsg());
\r
5103 SAY("computer starts playing white");
\r
5106 case IDM_MachineBlack:
\r
5107 MachineBlackEvent();
\r
5109 * refresh the tags dialog only if it's visible
\r
5111 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5113 tags = PGNTags(&gameInfo);
\r
5114 TagsPopUp(tags, CmailMsg());
\r
5117 SAY("computer starts playing black");
\r
5120 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5121 if(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED);
\r
5122 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5125 case IDM_TwoMachines:
\r
5126 TwoMachinesEvent();
\r
5129 * refresh the tags dialog only if it's visible
\r
5131 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5133 tags = PGNTags(&gameInfo);
\r
5134 TagsPopUp(tags, CmailMsg());
\r
5137 SAY("computer starts playing both sides");
\r
5140 case IDM_AnalysisMode:
\r
5141 if(AnalyzeModeEvent()) {
\r
5142 SAY("analyzing current position");
\r
5146 case IDM_AnalyzeFile:
\r
5147 AnalyzeFileEvent();
\r
5150 case IDM_IcsClient:
\r
5154 case IDM_EditGame:
\r
5155 case IDM_EditGame2:
\r
5160 case IDM_EditPosition:
\r
5161 case IDM_EditPosition2:
\r
5162 EditPositionEvent();
\r
5163 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5166 case IDM_Training:
\r
5170 case IDM_ShowGameList:
\r
5171 ShowGameListProc();
\r
5174 case IDM_EditProgs1:
\r
5175 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5178 case IDM_LoadProg1:
\r
5179 LoadEnginePopUp(hwndMain, 0);
\r
5182 case IDM_LoadProg2:
\r
5183 LoadEnginePopUp(hwndMain, 1);
\r
5186 case IDM_EditServers:
\r
5187 EditTagsPopUp(icsNames, &icsNames);
\r
5190 case IDM_EditTags:
\r
5195 case IDM_EditBook:
\r
5199 case IDM_EditComment:
\r
5201 if (commentUp && editComment) {
\r
5204 EditCommentEvent();
\r
5225 case IDM_CallFlag:
\r
5245 case IDM_StopObserving:
\r
5246 StopObservingEvent();
\r
5249 case IDM_StopExamining:
\r
5250 StopExaminingEvent();
\r
5254 UploadGameEvent();
\r
5257 case IDM_TypeInMove:
\r
5258 TypeInEvent('\000');
\r
5261 case IDM_TypeInName:
\r
5262 PopUpNameDialog('\000');
\r
5265 case IDM_Backward:
\r
5267 SetFocus(hwndMain);
\r
5274 SetFocus(hwndMain);
\r
5279 SetFocus(hwndMain);
\r
5284 SetFocus(hwndMain);
\r
5287 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5288 case OPT_GameListPrev:
\r
5289 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5293 RevertEvent(FALSE);
\r
5296 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5297 RevertEvent(TRUE);
\r
5300 case IDM_TruncateGame:
\r
5301 TruncateGameEvent();
\r
5308 case IDM_RetractMove:
\r
5309 RetractMoveEvent();
\r
5312 case IDM_FlipView:
\r
5313 flipView = !flipView;
\r
5314 DrawPosition(FALSE, NULL);
\r
5317 case IDM_FlipClock:
\r
5318 flipClock = !flipClock;
\r
5319 DisplayBothClocks();
\r
5323 case IDM_MuteSounds:
\r
5324 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5325 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5326 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5329 case IDM_GeneralOptions:
\r
5330 GeneralOptionsPopup(hwnd);
\r
5331 DrawPosition(TRUE, NULL);
\r
5334 case IDM_BoardOptions:
\r
5335 BoardOptionsPopup(hwnd);
\r
5338 case IDM_ThemeOptions:
\r
5339 ThemeOptionsPopup(hwnd);
\r
5342 case IDM_EnginePlayOptions:
\r
5343 EnginePlayOptionsPopup(hwnd);
\r
5346 case IDM_Engine1Options:
\r
5347 EngineOptionsPopup(hwnd, &first);
\r
5350 case IDM_Engine2Options:
\r
5352 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5353 EngineOptionsPopup(hwnd, &second);
\r
5356 case IDM_OptionsUCI:
\r
5357 UciOptionsPopup(hwnd);
\r
5361 TourneyPopup(hwnd);
\r
5364 case IDM_IcsOptions:
\r
5365 IcsOptionsPopup(hwnd);
\r
5369 FontsOptionsPopup(hwnd);
\r
5373 SoundOptionsPopup(hwnd);
\r
5376 case IDM_CommPort:
\r
5377 CommPortOptionsPopup(hwnd);
\r
5380 case IDM_LoadOptions:
\r
5381 LoadOptionsPopup(hwnd);
\r
5384 case IDM_SaveOptions:
\r
5385 SaveOptionsPopup(hwnd);
\r
5388 case IDM_TimeControl:
\r
5389 TimeControlOptionsPopup(hwnd);
\r
5392 case IDM_SaveSettings:
\r
5393 SaveSettings(settingsFileName);
\r
5396 case IDM_SaveSettingsOnExit:
\r
5397 saveSettingsOnExit = !saveSettingsOnExit;
\r
5398 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5399 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5400 MF_CHECKED : MF_UNCHECKED));
\r
5411 case IDM_AboutGame:
\r
5416 appData.debugMode = !appData.debugMode;
\r
5417 if (appData.debugMode) {
\r
5418 char dir[MSG_SIZ];
\r
5419 GetCurrentDirectory(MSG_SIZ, dir);
\r
5420 SetCurrentDirectory(installDir);
\r
5421 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5422 SetCurrentDirectory(dir);
\r
5423 setbuf(debugFP, NULL);
\r
5430 case IDM_HELPCONTENTS:
\r
5431 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5432 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5433 MessageBox (GetFocus(),
\r
5434 _("Unable to activate help"),
\r
5435 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5439 case IDM_HELPSEARCH:
\r
5440 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5441 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5442 MessageBox (GetFocus(),
\r
5443 _("Unable to activate help"),
\r
5444 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5448 case IDM_HELPHELP:
\r
5449 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5450 MessageBox (GetFocus(),
\r
5451 _("Unable to activate help"),
\r
5452 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5457 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5459 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5460 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5461 FreeProcInstance(lpProc);
\r
5464 case IDM_DirectCommand1:
\r
5465 AskQuestionEvent(_("Direct Command"),
\r
5466 _("Send to chess program:"), "", "1");
\r
5468 case IDM_DirectCommand2:
\r
5469 AskQuestionEvent(_("Direct Command"),
\r
5470 _("Send to second chess program:"), "", "2");
\r
5473 case EP_WhitePawn:
\r
5474 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5475 fromX = fromY = -1;
\r
5478 case EP_WhiteKnight:
\r
5479 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5480 fromX = fromY = -1;
\r
5483 case EP_WhiteBishop:
\r
5484 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5485 fromX = fromY = -1;
\r
5488 case EP_WhiteRook:
\r
5489 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5490 fromX = fromY = -1;
\r
5493 case EP_WhiteQueen:
\r
5494 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5495 fromX = fromY = -1;
\r
5498 case EP_WhiteFerz:
\r
5499 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5500 fromX = fromY = -1;
\r
5503 case EP_WhiteWazir:
\r
5504 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5505 fromX = fromY = -1;
\r
5508 case EP_WhiteAlfil:
\r
5509 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5510 fromX = fromY = -1;
\r
5513 case EP_WhiteCannon:
\r
5514 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5515 fromX = fromY = -1;
\r
5518 case EP_WhiteCardinal:
\r
5519 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5520 fromX = fromY = -1;
\r
5523 case EP_WhiteMarshall:
\r
5524 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5525 fromX = fromY = -1;
\r
5528 case EP_WhiteKing:
\r
5529 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5530 fromX = fromY = -1;
\r
5533 case EP_BlackPawn:
\r
5534 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5535 fromX = fromY = -1;
\r
5538 case EP_BlackKnight:
\r
5539 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5540 fromX = fromY = -1;
\r
5543 case EP_BlackBishop:
\r
5544 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5545 fromX = fromY = -1;
\r
5548 case EP_BlackRook:
\r
5549 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5550 fromX = fromY = -1;
\r
5553 case EP_BlackQueen:
\r
5554 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5555 fromX = fromY = -1;
\r
5558 case EP_BlackFerz:
\r
5559 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5560 fromX = fromY = -1;
\r
5563 case EP_BlackWazir:
\r
5564 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5565 fromX = fromY = -1;
\r
5568 case EP_BlackAlfil:
\r
5569 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5570 fromX = fromY = -1;
\r
5573 case EP_BlackCannon:
\r
5574 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5575 fromX = fromY = -1;
\r
5578 case EP_BlackCardinal:
\r
5579 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5580 fromX = fromY = -1;
\r
5583 case EP_BlackMarshall:
\r
5584 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5585 fromX = fromY = -1;
\r
5588 case EP_BlackKing:
\r
5589 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5590 fromX = fromY = -1;
\r
5593 case EP_EmptySquare:
\r
5594 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5595 fromX = fromY = -1;
\r
5598 case EP_ClearBoard:
\r
5599 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5600 fromX = fromY = -1;
\r
5604 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5605 fromX = fromY = -1;
\r
5609 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5610 fromX = fromY = -1;
\r
5614 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5615 fromX = fromY = -1;
\r
5619 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5620 fromX = fromY = -1;
\r
5624 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5625 fromX = fromY = -1;
\r
5629 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5630 fromX = fromY = -1;
\r
5634 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5635 fromX = fromY = -1;
\r
5639 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5640 fromX = fromY = -1;
\r
5644 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5645 fromX = fromY = -1;
\r
5649 barbaric = 0; appData.language = "";
\r
5650 TranslateMenus(0);
\r
5651 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5652 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5653 lastChecked = wmId;
\r
5657 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5658 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5660 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5661 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5662 TranslateMenus(0);
\r
5663 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5664 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5665 lastChecked = wmId;
\r
5668 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5674 case CLOCK_TIMER_ID:
\r
5675 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5676 clockTimerEvent = 0;
\r
5677 DecrementClocks(); /* call into back end */
\r
5679 case LOAD_GAME_TIMER_ID:
\r
5680 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5681 loadGameTimerEvent = 0;
\r
5682 AutoPlayGameLoop(); /* call into back end */
\r
5684 case ANALYSIS_TIMER_ID:
\r
5685 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5686 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5687 AnalysisPeriodicEvent(0);
\r
5689 KillTimer(hwnd, analysisTimerEvent);
\r
5690 analysisTimerEvent = 0;
\r
5693 case DELAYED_TIMER_ID:
\r
5694 KillTimer(hwnd, delayedTimerEvent);
\r
5695 delayedTimerEvent = 0;
\r
5696 delayedTimerCallback();
\r
5701 case WM_USER_Input:
\r
5702 InputEvent(hwnd, message, wParam, lParam);
\r
5705 /* [AS] Also move "attached" child windows */
\r
5706 case WM_WINDOWPOSCHANGING:
\r
5708 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5709 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5711 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5712 /* Window is moving */
\r
5715 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5716 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5717 rcMain.right = wpMain.x + wpMain.width;
\r
5718 rcMain.top = wpMain.y;
\r
5719 rcMain.bottom = wpMain.y + wpMain.height;
\r
5721 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5722 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5723 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5724 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5725 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5726 wpMain.x = lpwp->x;
\r
5727 wpMain.y = lpwp->y;
\r
5733 /* [AS] Snapping */
\r
5734 case WM_ENTERSIZEMOVE:
\r
5735 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5736 if (hwnd == hwndMain) {
\r
5737 doingSizing = TRUE;
\r
5740 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5744 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5745 if (hwnd == hwndMain) {
\r
5746 lastSizing = wParam;
\r
5751 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5752 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5754 case WM_EXITSIZEMOVE:
\r
5755 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5756 if (hwnd == hwndMain) {
\r
5758 doingSizing = FALSE;
\r
5759 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5760 GetClientRect(hwnd, &client);
\r
5761 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5763 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5765 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5768 case WM_DESTROY: /* message: window being destroyed */
\r
5769 PostQuitMessage(0);
\r
5773 if (hwnd == hwndMain) {
\r
5778 default: /* Passes it on if unprocessed */
\r
5779 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5786 /*---------------------------------------------------------------------------*\
\r
5788 * Misc utility routines
\r
5790 \*---------------------------------------------------------------------------*/
\r
5793 * Decent random number generator, at least not as bad as Windows
\r
5794 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5796 unsigned int randstate;
\r
5801 randstate = randstate * 1664525 + 1013904223;
\r
5802 return (int) randstate & 0x7fffffff;
\r
5806 mysrandom(unsigned int seed)
\r
5813 * returns TRUE if user selects a different color, FALSE otherwise
\r
5817 ChangeColor(HWND hwnd, COLORREF *which)
\r
5819 static BOOL firstTime = TRUE;
\r
5820 static DWORD customColors[16];
\r
5822 COLORREF newcolor;
\r
5827 /* Make initial colors in use available as custom colors */
\r
5828 /* Should we put the compiled-in defaults here instead? */
\r
5830 customColors[i++] = lightSquareColor & 0xffffff;
\r
5831 customColors[i++] = darkSquareColor & 0xffffff;
\r
5832 customColors[i++] = whitePieceColor & 0xffffff;
\r
5833 customColors[i++] = blackPieceColor & 0xffffff;
\r
5834 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5835 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5837 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5838 customColors[i++] = textAttribs[ccl].color;
\r
5840 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5841 firstTime = FALSE;
\r
5844 cc.lStructSize = sizeof(cc);
\r
5845 cc.hwndOwner = hwnd;
\r
5846 cc.hInstance = NULL;
\r
5847 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5848 cc.lpCustColors = (LPDWORD) customColors;
\r
5849 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5851 if (!ChooseColor(&cc)) return FALSE;
\r
5853 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5854 if (newcolor == *which) return FALSE;
\r
5855 *which = newcolor;
\r
5859 InitDrawingColors();
\r
5860 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5865 MyLoadSound(MySound *ms)
\r
5871 if (ms->data && ms->flag) free(ms->data);
\r
5874 switch (ms->name[0]) {
\r
5880 /* System sound from Control Panel. Don't preload here. */
\r
5884 if (ms->name[1] == NULLCHAR) {
\r
5885 /* "!" alone = silence */
\r
5888 /* Builtin wave resource. Error if not found. */
\r
5889 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5890 if (h == NULL) break;
\r
5891 ms->data = (void *)LoadResource(hInst, h);
\r
5892 ms->flag = 0; // not maloced, so cannot be freed!
\r
5893 if (h == NULL) break;
\r
5898 /* .wav file. Error if not found. */
\r
5899 f = fopen(ms->name, "rb");
\r
5900 if (f == NULL) break;
\r
5901 if (fstat(fileno(f), &st) < 0) break;
\r
5902 ms->data = malloc(st.st_size);
\r
5904 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5910 char buf[MSG_SIZ];
\r
5911 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5912 DisplayError(buf, GetLastError());
\r
5918 MyPlaySound(MySound *ms)
\r
5920 BOOLEAN ok = FALSE;
\r
5922 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5923 switch (ms->name[0]) {
\r
5925 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5930 /* System sound from Control Panel (deprecated feature).
\r
5931 "$" alone or an unset sound name gets default beep (still in use). */
\r
5932 if (ms->name[1]) {
\r
5933 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5935 if (!ok) ok = MessageBeep(MB_OK);
\r
5938 /* Builtin wave resource, or "!" alone for silence */
\r
5939 if (ms->name[1]) {
\r
5940 if (ms->data == NULL) return FALSE;
\r
5941 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5947 /* .wav file. Error if not found. */
\r
5948 if (ms->data == NULL) return FALSE;
\r
5949 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5952 /* Don't print an error: this can happen innocently if the sound driver
\r
5953 is busy; for instance, if another instance of WinBoard is playing
\r
5954 a sound at about the same time. */
\r
5960 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5963 OPENFILENAME *ofn;
\r
5964 static UINT *number; /* gross that this is static */
\r
5966 switch (message) {
\r
5967 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5968 /* Center the dialog over the application window */
\r
5969 ofn = (OPENFILENAME *) lParam;
\r
5970 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5971 number = (UINT *) ofn->lCustData;
\r
5972 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5976 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5977 Translate(hDlg, 1536);
\r
5978 return FALSE; /* Allow for further processing */
\r
5981 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5982 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5984 return FALSE; /* Allow for further processing */
\r
5990 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5992 static UINT *number;
\r
5993 OPENFILENAME *ofname;
\r
5996 case WM_INITDIALOG:
\r
5997 Translate(hdlg, DLG_IndexNumber);
\r
5998 ofname = (OPENFILENAME *)lParam;
\r
5999 number = (UINT *)(ofname->lCustData);
\r
6002 ofnot = (OFNOTIFY *)lParam;
\r
6003 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6004 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6013 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6014 char *nameFilt, char *dlgTitle, UINT *number,
\r
6015 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6017 OPENFILENAME openFileName;
\r
6018 char buf1[MSG_SIZ];
\r
6021 if (fileName == NULL) fileName = buf1;
\r
6022 if (defName == NULL) {
\r
6023 safeStrCpy(fileName, "*.", 3 );
\r
6024 strcat(fileName, defExt);
\r
6026 safeStrCpy(fileName, defName, MSG_SIZ );
\r
6028 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
6029 if (number) *number = 0;
\r
6031 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6032 openFileName.hwndOwner = hwnd;
\r
6033 openFileName.hInstance = (HANDLE) hInst;
\r
6034 openFileName.lpstrFilter = nameFilt;
\r
6035 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6036 openFileName.nMaxCustFilter = 0L;
\r
6037 openFileName.nFilterIndex = 1L;
\r
6038 openFileName.lpstrFile = fileName;
\r
6039 openFileName.nMaxFile = MSG_SIZ;
\r
6040 openFileName.lpstrFileTitle = fileTitle;
\r
6041 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6042 openFileName.lpstrInitialDir = NULL;
\r
6043 openFileName.lpstrTitle = dlgTitle;
\r
6044 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6045 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6046 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6047 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6048 openFileName.nFileOffset = 0;
\r
6049 openFileName.nFileExtension = 0;
\r
6050 openFileName.lpstrDefExt = defExt;
\r
6051 openFileName.lCustData = (LONG) number;
\r
6052 openFileName.lpfnHook = oldDialog ?
\r
6053 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6054 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6056 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6057 GetOpenFileName(&openFileName)) {
\r
6058 /* open the file */
\r
6059 f = fopen(openFileName.lpstrFile, write);
\r
6061 MessageBox(hwnd, _("File open failed"), NULL,
\r
6062 MB_OK|MB_ICONEXCLAMATION);
\r
6066 int err = CommDlgExtendedError();
\r
6067 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6076 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6078 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6081 * Get the first pop-up menu in the menu template. This is the
\r
6082 * menu that TrackPopupMenu displays.
\r
6084 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6085 TranslateOneMenu(10, hmenuTrackPopup);
\r
6087 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6090 * TrackPopup uses screen coordinates, so convert the
\r
6091 * coordinates of the mouse click to screen coordinates.
\r
6093 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6095 /* Draw and track the floating pop-up menu. */
\r
6096 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6097 pt.x, pt.y, 0, hwnd, NULL);
\r
6099 /* Destroy the menu.*/
\r
6100 DestroyMenu(hmenu);
\r
6105 int sizeX, sizeY, newSizeX, newSizeY;
\r
6107 } ResizeEditPlusButtonsClosure;
\r
6110 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6112 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6116 if (hChild == cl->hText) return TRUE;
\r
6117 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6118 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6119 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6120 ScreenToClient(cl->hDlg, &pt);
\r
6121 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6122 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6126 /* Resize a dialog that has a (rich) edit field filling most of
\r
6127 the top, with a row of buttons below */
\r
6129 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6132 int newTextHeight, newTextWidth;
\r
6133 ResizeEditPlusButtonsClosure cl;
\r
6135 /*if (IsIconic(hDlg)) return;*/
\r
6136 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6138 cl.hdwp = BeginDeferWindowPos(8);
\r
6140 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6141 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6142 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6143 if (newTextHeight < 0) {
\r
6144 newSizeY += -newTextHeight;
\r
6145 newTextHeight = 0;
\r
6147 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6148 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6154 cl.newSizeX = newSizeX;
\r
6155 cl.newSizeY = newSizeY;
\r
6156 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6158 EndDeferWindowPos(cl.hdwp);
\r
6161 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6163 RECT rChild, rParent;
\r
6164 int wChild, hChild, wParent, hParent;
\r
6165 int wScreen, hScreen, xNew, yNew;
\r
6168 /* Get the Height and Width of the child window */
\r
6169 GetWindowRect (hwndChild, &rChild);
\r
6170 wChild = rChild.right - rChild.left;
\r
6171 hChild = rChild.bottom - rChild.top;
\r
6173 /* Get the Height and Width of the parent window */
\r
6174 GetWindowRect (hwndParent, &rParent);
\r
6175 wParent = rParent.right - rParent.left;
\r
6176 hParent = rParent.bottom - rParent.top;
\r
6178 /* Get the display limits */
\r
6179 hdc = GetDC (hwndChild);
\r
6180 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6181 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6182 ReleaseDC(hwndChild, hdc);
\r
6184 /* Calculate new X position, then adjust for screen */
\r
6185 xNew = rParent.left + ((wParent - wChild) /2);
\r
6188 } else if ((xNew+wChild) > wScreen) {
\r
6189 xNew = wScreen - wChild;
\r
6192 /* Calculate new Y position, then adjust for screen */
\r
6194 yNew = rParent.top + ((hParent - hChild) /2);
\r
6197 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6202 } else if ((yNew+hChild) > hScreen) {
\r
6203 yNew = hScreen - hChild;
\r
6206 /* Set it, and return */
\r
6207 return SetWindowPos (hwndChild, NULL,
\r
6208 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6211 /* Center one window over another */
\r
6212 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6214 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6217 /*---------------------------------------------------------------------------*\
\r
6219 * Startup Dialog functions
\r
6221 \*---------------------------------------------------------------------------*/
\r
6223 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6225 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6227 while (*cd != NULL) {
\r
6228 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6234 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6236 char buf1[MAX_ARG_LEN];
\r
6239 if (str[0] == '@') {
\r
6240 FILE* f = fopen(str + 1, "r");
\r
6242 DisplayFatalError(str + 1, errno, 2);
\r
6245 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6247 buf1[len] = NULLCHAR;
\r
6251 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6254 char buf[MSG_SIZ];
\r
6255 char *end = strchr(str, '\n');
\r
6256 if (end == NULL) return;
\r
6257 memcpy(buf, str, end - str);
\r
6258 buf[end - str] = NULLCHAR;
\r
6259 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6265 SetStartupDialogEnables(HWND hDlg)
\r
6267 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6268 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6269 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6270 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6271 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6272 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6273 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6274 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6275 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6276 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6277 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6278 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6279 IsDlgButtonChecked(hDlg, OPT_View));
\r
6283 QuoteForFilename(char *filename)
\r
6285 int dquote, space;
\r
6286 dquote = strchr(filename, '"') != NULL;
\r
6287 space = strchr(filename, ' ') != NULL;
\r
6288 if (dquote || space) {
\r
6300 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6302 char buf[MSG_SIZ];
\r
6305 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6306 q = QuoteForFilename(nthcp);
\r
6307 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6308 if (*nthdir != NULLCHAR) {
\r
6309 q = QuoteForFilename(nthdir);
\r
6310 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6312 if (*nthcp == NULLCHAR) {
\r
6313 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6314 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6315 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6316 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6321 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6323 char buf[MSG_SIZ];
\r
6327 switch (message) {
\r
6328 case WM_INITDIALOG:
\r
6329 /* Center the dialog */
\r
6330 CenterWindow (hDlg, GetDesktopWindow());
\r
6331 Translate(hDlg, DLG_Startup);
\r
6332 /* Initialize the dialog items */
\r
6333 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6334 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6335 firstChessProgramNames);
\r
6336 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6337 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6338 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6339 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6340 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6341 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6342 if (*appData.icsHelper != NULLCHAR) {
\r
6343 char *q = QuoteForFilename(appData.icsHelper);
\r
6344 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6346 if (*appData.icsHost == NULLCHAR) {
\r
6347 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6348 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6349 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6350 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6351 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6354 if (appData.icsActive) {
\r
6355 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6357 else if (appData.noChessProgram) {
\r
6358 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6361 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6364 SetStartupDialogEnables(hDlg);
\r
6368 switch (LOWORD(wParam)) {
\r
6370 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6371 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6372 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6374 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6375 ParseArgs(StringGet, &p);
\r
6376 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6377 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6379 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6380 ParseArgs(StringGet, &p);
\r
6381 SwapEngines(singleList); // ... and then make it 'second'
\r
6383 appData.noChessProgram = FALSE;
\r
6384 appData.icsActive = FALSE;
\r
6385 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6386 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6387 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6389 ParseArgs(StringGet, &p);
\r
6390 if (appData.zippyPlay) {
\r
6391 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6392 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6394 ParseArgs(StringGet, &p);
\r
6396 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6397 appData.noChessProgram = TRUE;
\r
6398 appData.icsActive = FALSE;
\r
6400 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6401 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6404 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6405 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6407 ParseArgs(StringGet, &p);
\r
6409 EndDialog(hDlg, TRUE);
\r
6416 case IDM_HELPCONTENTS:
\r
6417 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6418 MessageBox (GetFocus(),
\r
6419 _("Unable to activate help"),
\r
6420 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6425 SetStartupDialogEnables(hDlg);
\r
6433 /*---------------------------------------------------------------------------*\
\r
6435 * About box dialog functions
\r
6437 \*---------------------------------------------------------------------------*/
\r
6439 /* Process messages for "About" dialog box */
\r
6441 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6443 switch (message) {
\r
6444 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6445 /* Center the dialog over the application window */
\r
6446 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6447 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6448 Translate(hDlg, ABOUTBOX);
\r
6452 case WM_COMMAND: /* message: received a command */
\r
6453 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6454 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6455 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6463 /*---------------------------------------------------------------------------*\
\r
6465 * Comment Dialog functions
\r
6467 \*---------------------------------------------------------------------------*/
\r
6470 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6472 static HANDLE hwndText = NULL;
\r
6473 int len, newSizeX, newSizeY;
\r
6474 static int sizeX, sizeY;
\r
6479 switch (message) {
\r
6480 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6481 /* Initialize the dialog items */
\r
6482 Translate(hDlg, DLG_EditComment);
\r
6483 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6484 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6485 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6486 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6487 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6488 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6489 SetWindowText(hDlg, commentTitle);
\r
6490 if (editComment) {
\r
6491 SetFocus(hwndText);
\r
6493 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6495 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6496 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6497 MAKELPARAM(FALSE, 0));
\r
6498 /* Size and position the dialog */
\r
6499 if (!commentDialog) {
\r
6500 commentDialog = hDlg;
\r
6501 GetClientRect(hDlg, &rect);
\r
6502 sizeX = rect.right;
\r
6503 sizeY = rect.bottom;
\r
6504 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6505 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6506 WINDOWPLACEMENT wp;
\r
6507 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6508 wp.length = sizeof(WINDOWPLACEMENT);
\r
6510 wp.showCmd = SW_SHOW;
\r
6511 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6512 wp.rcNormalPosition.left = wpComment.x;
\r
6513 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6514 wp.rcNormalPosition.top = wpComment.y;
\r
6515 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6516 SetWindowPlacement(hDlg, &wp);
\r
6518 GetClientRect(hDlg, &rect);
\r
6519 newSizeX = rect.right;
\r
6520 newSizeY = rect.bottom;
\r
6521 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6522 newSizeX, newSizeY);
\r
6527 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6530 case WM_COMMAND: /* message: received a command */
\r
6531 switch (LOWORD(wParam)) {
\r
6533 if (editComment) {
\r
6535 /* Read changed options from the dialog box */
\r
6536 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6537 len = GetWindowTextLength(hwndText);
\r
6538 str = (char *) malloc(len + 1);
\r
6539 GetWindowText(hwndText, str, len + 1);
\r
6548 ReplaceComment(commentIndex, str);
\r
6555 case OPT_CancelComment:
\r
6559 case OPT_ClearComment:
\r
6560 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6563 case OPT_EditComment:
\r
6564 EditCommentEvent();
\r
6572 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6573 if( wParam == OPT_CommentText ) {
\r
6574 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6576 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6577 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6581 pt.x = LOWORD( lpMF->lParam );
\r
6582 pt.y = HIWORD( lpMF->lParam );
\r
6584 if(lpMF->msg == WM_CHAR) {
\r
6586 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6587 index = sel.cpMin;
\r
6589 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6591 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6592 len = GetWindowTextLength(hwndText);
\r
6593 str = (char *) malloc(len + 1);
\r
6594 GetWindowText(hwndText, str, len + 1);
\r
6595 ReplaceComment(commentIndex, str);
\r
6596 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6597 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6600 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6601 lpMF->msg = WM_USER;
\r
6609 newSizeX = LOWORD(lParam);
\r
6610 newSizeY = HIWORD(lParam);
\r
6611 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6616 case WM_GETMINMAXINFO:
\r
6617 /* Prevent resizing window too small */
\r
6618 mmi = (MINMAXINFO *) lParam;
\r
6619 mmi->ptMinTrackSize.x = 100;
\r
6620 mmi->ptMinTrackSize.y = 100;
\r
6627 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6632 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6634 if (str == NULL) str = "";
\r
6635 p = (char *) malloc(2 * strlen(str) + 2);
\r
6638 if (*str == '\n') *q++ = '\r';
\r
6642 if (commentText != NULL) free(commentText);
\r
6644 commentIndex = index;
\r
6645 commentTitle = title;
\r
6647 editComment = edit;
\r
6649 if (commentDialog) {
\r
6650 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6651 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6653 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6654 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6655 hwndMain, (DLGPROC)lpProc);
\r
6656 FreeProcInstance(lpProc);
\r
6662 /*---------------------------------------------------------------------------*\
\r
6664 * Type-in move dialog functions
\r
6666 \*---------------------------------------------------------------------------*/
\r
6669 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6671 char move[MSG_SIZ];
\r
6674 switch (message) {
\r
6675 case WM_INITDIALOG:
\r
6676 move[0] = (char) lParam;
\r
6677 move[1] = NULLCHAR;
\r
6678 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6679 Translate(hDlg, DLG_TypeInMove);
\r
6680 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6681 SetWindowText(hInput, move);
\r
6683 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6687 switch (LOWORD(wParam)) {
\r
6690 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6691 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6692 TypeInDoneEvent(move);
\r
6693 EndDialog(hDlg, TRUE);
\r
6696 EndDialog(hDlg, FALSE);
\r
6707 PopUpMoveDialog(char firstchar)
\r
6711 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6712 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6713 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6714 FreeProcInstance(lpProc);
\r
6717 /*---------------------------------------------------------------------------*\
\r
6719 * Type-in name dialog functions
\r
6721 \*---------------------------------------------------------------------------*/
\r
6724 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6726 char move[MSG_SIZ];
\r
6729 switch (message) {
\r
6730 case WM_INITDIALOG:
\r
6731 move[0] = (char) lParam;
\r
6732 move[1] = NULLCHAR;
\r
6733 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6734 Translate(hDlg, DLG_TypeInName);
\r
6735 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6736 SetWindowText(hInput, move);
\r
6738 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6742 switch (LOWORD(wParam)) {
\r
6744 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6745 appData.userName = strdup(move);
\r
6746 SetUserLogo(); DisplayLogos();
\r
6748 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6749 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6750 DisplayTitle(move);
\r
6754 EndDialog(hDlg, TRUE);
\r
6757 EndDialog(hDlg, FALSE);
\r
6768 PopUpNameDialog(char firstchar)
\r
6772 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6773 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6774 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6775 FreeProcInstance(lpProc);
\r
6778 /*---------------------------------------------------------------------------*\
\r
6782 \*---------------------------------------------------------------------------*/
\r
6784 /* Nonmodal error box */
\r
6785 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6786 WPARAM wParam, LPARAM lParam);
\r
6789 ErrorPopUp(char *title, char *content)
\r
6793 BOOLEAN modal = hwndMain == NULL;
\r
6811 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6812 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6815 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6817 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6818 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6819 hwndMain, (DLGPROC)lpProc);
\r
6820 FreeProcInstance(lpProc);
\r
6827 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6828 if (errorDialog == NULL) return;
\r
6829 DestroyWindow(errorDialog);
\r
6830 errorDialog = NULL;
\r
6831 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6835 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6839 switch (message) {
\r
6840 case WM_INITDIALOG:
\r
6841 GetWindowRect(hDlg, &rChild);
\r
6844 SetWindowPos(hDlg, NULL, rChild.left,
\r
6845 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6846 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6850 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6851 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6852 and it doesn't work when you resize the dialog.
\r
6853 For now, just give it a default position.
\r
6855 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6856 Translate(hDlg, DLG_Error);
\r
6858 errorDialog = hDlg;
\r
6859 SetWindowText(hDlg, errorTitle);
\r
6860 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6864 switch (LOWORD(wParam)) {
\r
6867 if (errorDialog == hDlg) errorDialog = NULL;
\r
6868 DestroyWindow(hDlg);
\r
6880 HWND gothicDialog = NULL;
\r
6883 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6886 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6888 switch (message) {
\r
6889 case WM_INITDIALOG:
\r
6890 GetWindowRect(hDlg, &rChild);
\r
6892 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6896 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6897 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6898 and it doesn't work when you resize the dialog.
\r
6899 For now, just give it a default position.
\r
6901 gothicDialog = hDlg;
\r
6902 SetWindowText(hDlg, errorTitle);
\r
6903 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6907 switch (LOWORD(wParam)) {
\r
6910 if (errorDialog == hDlg) errorDialog = NULL;
\r
6911 DestroyWindow(hDlg);
\r
6923 GothicPopUp(char *title, VariantClass variant)
\r
6926 static char *lastTitle;
\r
6928 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6929 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6931 if(lastTitle != title && gothicDialog != NULL) {
\r
6932 DestroyWindow(gothicDialog);
\r
6933 gothicDialog = NULL;
\r
6935 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6936 title = lastTitle;
\r
6937 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6938 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6939 hwndMain, (DLGPROC)lpProc);
\r
6940 FreeProcInstance(lpProc);
\r
6945 /*---------------------------------------------------------------------------*\
\r
6947 * Ics Interaction console functions
\r
6949 \*---------------------------------------------------------------------------*/
\r
6951 #define HISTORY_SIZE 64
\r
6952 static char *history[HISTORY_SIZE];
\r
6953 int histIn = 0, histP = 0;
\r
6957 SaveInHistory(char *cmd)
\r
6959 if (history[histIn] != NULL) {
\r
6960 free(history[histIn]);
\r
6961 history[histIn] = NULL;
\r
6963 if (*cmd == NULLCHAR) return;
\r
6964 history[histIn] = StrSave(cmd);
\r
6965 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6966 if (history[histIn] != NULL) {
\r
6967 free(history[histIn]);
\r
6969 history[histIn] = NULL;
\r
6975 PrevInHistory(char *cmd)
\r
6978 if (histP == histIn) {
\r
6979 if (history[histIn] != NULL) free(history[histIn]);
\r
6980 history[histIn] = StrSave(cmd);
\r
6982 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6983 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6985 return history[histP];
\r
6991 if (histP == histIn) return NULL;
\r
6992 histP = (histP + 1) % HISTORY_SIZE;
\r
6993 return history[histP];
\r
6997 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7001 hmenu = LoadMenu(hInst, "TextMenu");
\r
7002 h = GetSubMenu(hmenu, 0);
\r
7004 if (strcmp(e->item, "-") == 0) {
\r
7005 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7006 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
7007 int flags = MF_STRING, j = 0;
\r
7008 if (e->item[0] == '|') {
\r
7009 flags |= MF_MENUBARBREAK;
\r
7012 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
7013 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
7021 WNDPROC consoleTextWindowProc;
\r
7024 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7026 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7027 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7031 SetWindowText(hInput, command);
\r
7033 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7035 sel.cpMin = 999999;
\r
7036 sel.cpMax = 999999;
\r
7037 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7042 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7043 if (sel.cpMin == sel.cpMax) {
\r
7044 /* Expand to surrounding word */
\r
7047 tr.chrg.cpMax = sel.cpMin;
\r
7048 tr.chrg.cpMin = --sel.cpMin;
\r
7049 if (sel.cpMin < 0) break;
\r
7050 tr.lpstrText = name;
\r
7051 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7052 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7056 tr.chrg.cpMin = sel.cpMax;
\r
7057 tr.chrg.cpMax = ++sel.cpMax;
\r
7058 tr.lpstrText = name;
\r
7059 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7060 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7063 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7064 MessageBeep(MB_ICONEXCLAMATION);
\r
7068 tr.lpstrText = name;
\r
7069 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7071 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7072 MessageBeep(MB_ICONEXCLAMATION);
\r
7075 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7078 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7079 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7080 SetWindowText(hInput, buf);
\r
7081 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7083 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7084 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7085 SetWindowText(hInput, buf);
\r
7086 sel.cpMin = 999999;
\r
7087 sel.cpMax = 999999;
\r
7088 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7094 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7099 switch (message) {
\r
7101 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7102 if(wParam=='R') return 0;
\r
7105 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7108 sel.cpMin = 999999;
\r
7109 sel.cpMax = 999999;
\r
7110 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7111 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7116 if(wParam != '\022') {
\r
7117 if (wParam == '\t') {
\r
7118 if (GetKeyState(VK_SHIFT) < 0) {
\r
7120 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7121 if (buttonDesc[0].hwnd) {
\r
7122 SetFocus(buttonDesc[0].hwnd);
\r
7124 SetFocus(hwndMain);
\r
7128 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7131 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7132 JAWS_DELETE( SetFocus(hInput); )
\r
7133 SendMessage(hInput, message, wParam, lParam);
\r
7136 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7138 case WM_RBUTTONDOWN:
\r
7139 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7140 /* Move selection here if it was empty */
\r
7142 pt.x = LOWORD(lParam);
\r
7143 pt.y = HIWORD(lParam);
\r
7144 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7145 if (sel.cpMin == sel.cpMax) {
\r
7146 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7147 sel.cpMax = sel.cpMin;
\r
7148 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7150 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7151 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7153 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7154 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7155 if (sel.cpMin == sel.cpMax) {
\r
7156 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7157 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7159 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7160 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7162 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7163 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7164 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7165 MenuPopup(hwnd, pt, hmenu, -1);
\r
7169 case WM_RBUTTONUP:
\r
7170 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7171 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7172 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7176 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7178 return SendMessage(hInput, message, wParam, lParam);
\r
7179 case WM_MBUTTONDOWN:
\r
7180 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7182 switch (LOWORD(wParam)) {
\r
7183 case IDM_QuickPaste:
\r
7185 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7186 if (sel.cpMin == sel.cpMax) {
\r
7187 MessageBeep(MB_ICONEXCLAMATION);
\r
7190 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7191 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7192 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7197 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7200 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7203 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7207 int i = LOWORD(wParam) - IDM_CommandX;
\r
7208 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7209 icsTextMenuEntry[i].command != NULL) {
\r
7210 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7211 icsTextMenuEntry[i].getname,
\r
7212 icsTextMenuEntry[i].immediate);
\r
7220 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7223 WNDPROC consoleInputWindowProc;
\r
7226 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7228 char buf[MSG_SIZ];
\r
7230 static BOOL sendNextChar = FALSE;
\r
7231 static BOOL quoteNextChar = FALSE;
\r
7232 InputSource *is = consoleInputSource;
\r
7236 switch (message) {
\r
7238 if (!appData.localLineEditing || sendNextChar) {
\r
7239 is->buf[0] = (CHAR) wParam;
\r
7241 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7242 sendNextChar = FALSE;
\r
7245 if (quoteNextChar) {
\r
7246 buf[0] = (char) wParam;
\r
7247 buf[1] = NULLCHAR;
\r
7248 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7249 quoteNextChar = FALSE;
\r
7253 case '\r': /* Enter key */
\r
7254 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7255 if (consoleEcho) SaveInHistory(is->buf);
\r
7256 is->buf[is->count++] = '\n';
\r
7257 is->buf[is->count] = NULLCHAR;
\r
7258 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7259 if (consoleEcho) {
\r
7260 ConsoleOutput(is->buf, is->count, TRUE);
\r
7261 } else if (appData.localLineEditing) {
\r
7262 ConsoleOutput("\n", 1, TRUE);
\r
7265 case '\033': /* Escape key */
\r
7266 SetWindowText(hwnd, "");
\r
7267 cf.cbSize = sizeof(CHARFORMAT);
\r
7268 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7269 if (consoleEcho) {
\r
7270 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7272 cf.crTextColor = COLOR_ECHOOFF;
\r
7274 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7275 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7277 case '\t': /* Tab key */
\r
7278 if (GetKeyState(VK_SHIFT) < 0) {
\r
7280 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7283 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7284 if (buttonDesc[0].hwnd) {
\r
7285 SetFocus(buttonDesc[0].hwnd);
\r
7287 SetFocus(hwndMain);
\r
7291 case '\023': /* Ctrl+S */
\r
7292 sendNextChar = TRUE;
\r
7294 case '\021': /* Ctrl+Q */
\r
7295 quoteNextChar = TRUE;
\r
7305 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7306 p = PrevInHistory(buf);
\r
7308 SetWindowText(hwnd, p);
\r
7309 sel.cpMin = 999999;
\r
7310 sel.cpMax = 999999;
\r
7311 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7316 p = NextInHistory();
\r
7318 SetWindowText(hwnd, p);
\r
7319 sel.cpMin = 999999;
\r
7320 sel.cpMax = 999999;
\r
7321 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7327 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7331 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7335 case WM_MBUTTONDOWN:
\r
7336 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7337 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7339 case WM_RBUTTONUP:
\r
7340 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7341 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7342 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7346 hmenu = LoadMenu(hInst, "InputMenu");
\r
7347 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7348 if (sel.cpMin == sel.cpMax) {
\r
7349 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7350 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7352 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7353 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7355 pt.x = LOWORD(lParam);
\r
7356 pt.y = HIWORD(lParam);
\r
7357 MenuPopup(hwnd, pt, hmenu, -1);
\r
7361 switch (LOWORD(wParam)) {
\r
7363 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7365 case IDM_SelectAll:
\r
7367 sel.cpMax = -1; /*999999?*/
\r
7368 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7371 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7374 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7377 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7382 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7385 #define CO_MAX 100000
\r
7386 #define CO_TRIM 1000
\r
7389 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7391 static SnapData sd;
\r
7392 HWND hText, hInput;
\r
7394 static int sizeX, sizeY;
\r
7395 int newSizeX, newSizeY;
\r
7399 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7400 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7402 switch (message) {
\r
7404 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7406 ENLINK *pLink = (ENLINK*)lParam;
\r
7407 if (pLink->msg == WM_LBUTTONUP)
\r
7411 tr.chrg = pLink->chrg;
\r
7412 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7413 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7414 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7415 free(tr.lpstrText);
\r
7419 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7420 hwndConsole = hDlg;
\r
7422 consoleTextWindowProc = (WNDPROC)
\r
7423 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7424 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7425 consoleInputWindowProc = (WNDPROC)
\r
7426 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7427 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7428 Colorize(ColorNormal, TRUE);
\r
7429 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7430 ChangedConsoleFont();
\r
7431 GetClientRect(hDlg, &rect);
\r
7432 sizeX = rect.right;
\r
7433 sizeY = rect.bottom;
\r
7434 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7435 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7436 WINDOWPLACEMENT wp;
\r
7437 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7438 wp.length = sizeof(WINDOWPLACEMENT);
\r
7440 wp.showCmd = SW_SHOW;
\r
7441 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7442 wp.rcNormalPosition.left = wpConsole.x;
\r
7443 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7444 wp.rcNormalPosition.top = wpConsole.y;
\r
7445 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7446 SetWindowPlacement(hDlg, &wp);
\r
7449 // [HGM] Chessknight's change 2004-07-13
\r
7450 else { /* Determine Defaults */
\r
7451 WINDOWPLACEMENT wp;
\r
7452 wpConsole.x = wpMain.width + 1;
\r
7453 wpConsole.y = wpMain.y;
\r
7454 wpConsole.width = screenWidth - wpMain.width;
\r
7455 wpConsole.height = wpMain.height;
\r
7456 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7457 wp.length = sizeof(WINDOWPLACEMENT);
\r
7459 wp.showCmd = SW_SHOW;
\r
7460 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7461 wp.rcNormalPosition.left = wpConsole.x;
\r
7462 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7463 wp.rcNormalPosition.top = wpConsole.y;
\r
7464 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7465 SetWindowPlacement(hDlg, &wp);
\r
7468 // Allow hText to highlight URLs and send notifications on them
\r
7469 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7470 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7471 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7472 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7486 if (IsIconic(hDlg)) break;
\r
7487 newSizeX = LOWORD(lParam);
\r
7488 newSizeY = HIWORD(lParam);
\r
7489 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7490 RECT rectText, rectInput;
\r
7492 int newTextHeight, newTextWidth;
\r
7493 GetWindowRect(hText, &rectText);
\r
7494 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7495 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7496 if (newTextHeight < 0) {
\r
7497 newSizeY += -newTextHeight;
\r
7498 newTextHeight = 0;
\r
7500 SetWindowPos(hText, NULL, 0, 0,
\r
7501 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7502 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7503 pt.x = rectInput.left;
\r
7504 pt.y = rectInput.top + newSizeY - sizeY;
\r
7505 ScreenToClient(hDlg, &pt);
\r
7506 SetWindowPos(hInput, NULL,
\r
7507 pt.x, pt.y, /* needs client coords */
\r
7508 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7509 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7515 case WM_GETMINMAXINFO:
\r
7516 /* Prevent resizing window too small */
\r
7517 mmi = (MINMAXINFO *) lParam;
\r
7518 mmi->ptMinTrackSize.x = 100;
\r
7519 mmi->ptMinTrackSize.y = 100;
\r
7522 /* [AS] Snapping */
\r
7523 case WM_ENTERSIZEMOVE:
\r
7524 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7527 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7530 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7532 case WM_EXITSIZEMOVE:
\r
7533 UpdateICSWidth(hText);
\r
7534 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7537 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7545 if (hwndConsole) return;
\r
7546 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7547 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7552 ConsoleOutput(char* data, int length, int forceVisible)
\r
7557 char buf[CO_MAX+1];
\r
7560 static int delayLF = 0;
\r
7561 CHARRANGE savesel, sel;
\r
7563 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7571 while (length--) {
\r
7579 } else if (*p == '\007') {
\r
7580 MyPlaySound(&sounds[(int)SoundBell]);
\r
7587 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7588 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7589 /* Save current selection */
\r
7590 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7591 exlen = GetWindowTextLength(hText);
\r
7592 /* Find out whether current end of text is visible */
\r
7593 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7594 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7595 /* Trim existing text if it's too long */
\r
7596 if (exlen + (q - buf) > CO_MAX) {
\r
7597 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7600 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7601 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7603 savesel.cpMin -= trim;
\r
7604 savesel.cpMax -= trim;
\r
7605 if (exlen < 0) exlen = 0;
\r
7606 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7607 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7609 /* Append the new text */
\r
7610 sel.cpMin = exlen;
\r
7611 sel.cpMax = exlen;
\r
7612 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7613 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7614 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7615 if (forceVisible || exlen == 0 ||
\r
7616 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7617 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7618 /* Scroll to make new end of text visible if old end of text
\r
7619 was visible or new text is an echo of user typein */
\r
7620 sel.cpMin = 9999999;
\r
7621 sel.cpMax = 9999999;
\r
7622 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7623 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7624 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7625 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7627 if (savesel.cpMax == exlen || forceVisible) {
\r
7628 /* Move insert point to new end of text if it was at the old
\r
7629 end of text or if the new text is an echo of user typein */
\r
7630 sel.cpMin = 9999999;
\r
7631 sel.cpMax = 9999999;
\r
7632 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7634 /* Restore previous selection */
\r
7635 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7637 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7644 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7648 COLORREF oldFg, oldBg;
\r
7652 if(copyNumber > 1)
\r
7653 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7655 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7656 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7657 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7660 rect.right = x + squareSize;
\r
7662 rect.bottom = y + squareSize;
\r
7665 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7666 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7667 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7668 &rect, str, strlen(str), NULL);
\r
7670 (void) SetTextColor(hdc, oldFg);
\r
7671 (void) SetBkColor(hdc, oldBg);
\r
7672 (void) SelectObject(hdc, oldFont);
\r
7676 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7677 RECT *rect, char *color, char *flagFell)
\r
7681 COLORREF oldFg, oldBg;
\r
7684 if (twoBoards && partnerUp) return;
\r
7685 if (appData.clockMode) {
\r
7686 if (tinyLayout == 2)
\r
7687 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7689 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7696 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7697 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7699 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7700 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7703 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7707 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7708 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7709 rect, str, strlen(str), NULL);
\r
7710 if(logoHeight > 0 && appData.clockMode) {
\r
7712 str += strlen(color)+2;
\r
7713 r.top = rect->top + logoHeight/2;
\r
7714 r.left = rect->left;
\r
7715 r.right = rect->right;
\r
7716 r.bottom = rect->bottom;
\r
7717 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7718 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7719 &r, str, strlen(str), NULL);
\r
7721 (void) SetTextColor(hdc, oldFg);
\r
7722 (void) SetBkColor(hdc, oldBg);
\r
7723 (void) SelectObject(hdc, oldFont);
\r
7728 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7734 if( count <= 0 ) {
\r
7735 if (appData.debugMode) {
\r
7736 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7739 return ERROR_INVALID_USER_BUFFER;
\r
7742 ResetEvent(ovl->hEvent);
\r
7743 ovl->Offset = ovl->OffsetHigh = 0;
\r
7744 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7748 err = GetLastError();
\r
7749 if (err == ERROR_IO_PENDING) {
\r
7750 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7754 err = GetLastError();
\r
7761 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7766 ResetEvent(ovl->hEvent);
\r
7767 ovl->Offset = ovl->OffsetHigh = 0;
\r
7768 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7772 err = GetLastError();
\r
7773 if (err == ERROR_IO_PENDING) {
\r
7774 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7778 err = GetLastError();
\r
7785 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7786 void CheckForInputBufferFull( InputSource * is )
\r
7788 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7789 /* Look for end of line */
\r
7790 char * p = is->buf;
\r
7792 while( p < is->next && *p != '\n' ) {
\r
7796 if( p >= is->next ) {
\r
7797 if (appData.debugMode) {
\r
7798 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7801 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7802 is->count = (DWORD) -1;
\r
7803 is->next = is->buf;
\r
7809 InputThread(LPVOID arg)
\r
7814 is = (InputSource *) arg;
\r
7815 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7816 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7817 while (is->hThread != NULL) {
\r
7818 is->error = DoReadFile(is->hFile, is->next,
\r
7819 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7820 &is->count, &ovl);
\r
7821 if (is->error == NO_ERROR) {
\r
7822 is->next += is->count;
\r
7824 if (is->error == ERROR_BROKEN_PIPE) {
\r
7825 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7828 is->count = (DWORD) -1;
\r
7829 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7834 CheckForInputBufferFull( is );
\r
7836 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7838 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7840 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7843 CloseHandle(ovl.hEvent);
\r
7844 CloseHandle(is->hFile);
\r
7846 if (appData.debugMode) {
\r
7847 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7854 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7856 NonOvlInputThread(LPVOID arg)
\r
7863 is = (InputSource *) arg;
\r
7864 while (is->hThread != NULL) {
\r
7865 is->error = ReadFile(is->hFile, is->next,
\r
7866 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7867 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7868 if (is->error == NO_ERROR) {
\r
7869 /* Change CRLF to LF */
\r
7870 if (is->next > is->buf) {
\r
7872 i = is->count + 1;
\r
7880 if (prev == '\r' && *p == '\n') {
\r
7892 if (is->error == ERROR_BROKEN_PIPE) {
\r
7893 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7896 is->count = (DWORD) -1;
\r
7900 CheckForInputBufferFull( is );
\r
7902 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7904 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7906 if (is->count < 0) break; /* Quit on error */
\r
7908 CloseHandle(is->hFile);
\r
7913 SocketInputThread(LPVOID arg)
\r
7917 is = (InputSource *) arg;
\r
7918 while (is->hThread != NULL) {
\r
7919 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7920 if ((int)is->count == SOCKET_ERROR) {
\r
7921 is->count = (DWORD) -1;
\r
7922 is->error = WSAGetLastError();
\r
7924 is->error = NO_ERROR;
\r
7925 is->next += is->count;
\r
7926 if (is->count == 0 && is->second == is) {
\r
7927 /* End of file on stderr; quit with no message */
\r
7931 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7933 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7935 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7941 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7945 is = (InputSource *) lParam;
\r
7946 if (is->lineByLine) {
\r
7947 /* Feed in lines one by one */
\r
7948 char *p = is->buf;
\r
7950 while (q < is->next) {
\r
7951 if (*q++ == '\n') {
\r
7952 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7957 /* Move any partial line to the start of the buffer */
\r
7959 while (p < is->next) {
\r
7964 if (is->error != NO_ERROR || is->count == 0) {
\r
7965 /* Notify backend of the error. Note: If there was a partial
\r
7966 line at the end, it is not flushed through. */
\r
7967 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7970 /* Feed in the whole chunk of input at once */
\r
7971 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7972 is->next = is->buf;
\r
7976 /*---------------------------------------------------------------------------*\
\r
7978 * Menu enables. Used when setting various modes.
\r
7980 \*---------------------------------------------------------------------------*/
\r
7988 GreyRevert(Boolean grey)
\r
7989 { // [HGM] vari: for retracting variations in local mode
\r
7990 HMENU hmenu = GetMenu(hwndMain);
\r
7991 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7992 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7996 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7998 while (enab->item > 0) {
\r
7999 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8004 Enables gnuEnables[] = {
\r
8005 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8006 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8007 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8008 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8020 // Needed to switch from ncp to GNU mode on Engine Load
\r
8021 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8022 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8023 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8024 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8025 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8026 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8027 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
8028 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8029 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
8031 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8032 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8033 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8034 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8038 Enables icsEnables[] = {
\r
8039 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8042 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8043 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8047 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8055 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8056 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8063 Enables zippyEnables[] = {
\r
8064 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8065 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8066 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8067 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8072 Enables ncpEnables[] = {
\r
8073 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8075 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8076 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8077 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8078 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8079 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8080 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8081 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8082 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8083 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8084 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8085 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8086 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8087 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8088 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8089 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8090 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8091 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8092 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8093 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8094 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8098 Enables trainingOnEnables[] = {
\r
8099 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8111 Enables trainingOffEnables[] = {
\r
8112 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8113 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8114 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8115 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8116 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8117 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8118 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8119 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8120 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8124 /* These modify either ncpEnables or gnuEnables */
\r
8125 Enables cmailEnables[] = {
\r
8126 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8129 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8130 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8132 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8136 Enables machineThinkingEnables[] = {
\r
8137 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8138 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8139 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8140 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8141 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8142 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8143 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8144 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8145 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8146 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8147 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8148 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8149 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8150 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8151 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8152 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8156 Enables userThinkingEnables[] = {
\r
8157 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8158 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8159 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8160 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8161 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8162 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8163 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8164 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8165 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8166 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8167 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8168 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8169 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8170 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8171 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8172 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8176 /*---------------------------------------------------------------------------*\
\r
8178 * Front-end interface functions exported by XBoard.
\r
8179 * Functions appear in same order as prototypes in frontend.h.
\r
8181 \*---------------------------------------------------------------------------*/
\r
8183 CheckMark(UINT item, int state)
\r
8185 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8191 static UINT prevChecked = 0;
\r
8192 static int prevPausing = 0;
\r
8195 if (pausing != prevPausing) {
\r
8196 prevPausing = pausing;
\r
8197 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8198 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8199 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8202 switch (gameMode) {
\r
8203 case BeginningOfGame:
\r
8204 if (appData.icsActive)
\r
8205 nowChecked = IDM_IcsClient;
\r
8206 else if (appData.noChessProgram)
\r
8207 nowChecked = IDM_EditGame;
\r
8209 nowChecked = IDM_MachineBlack;
\r
8211 case MachinePlaysBlack:
\r
8212 nowChecked = IDM_MachineBlack;
\r
8214 case MachinePlaysWhite:
\r
8215 nowChecked = IDM_MachineWhite;
\r
8217 case TwoMachinesPlay:
\r
8218 nowChecked = IDM_TwoMachines;
\r
8221 nowChecked = IDM_AnalysisMode;
\r
8224 nowChecked = IDM_AnalyzeFile;
\r
8227 nowChecked = IDM_EditGame;
\r
8229 case PlayFromGameFile:
\r
8230 nowChecked = IDM_LoadGame;
\r
8232 case EditPosition:
\r
8233 nowChecked = IDM_EditPosition;
\r
8236 nowChecked = IDM_Training;
\r
8238 case IcsPlayingWhite:
\r
8239 case IcsPlayingBlack:
\r
8240 case IcsObserving:
\r
8242 nowChecked = IDM_IcsClient;
\r
8249 if(prevChecked == IDM_TwoMachine) // [HGM] 'Machine Match' might have gotten disabled when stopping match
\r
8250 EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED)
\r
8251 CheckMark(prevChecked, MF_UNCHECKED);
\r
8252 CheckMark(nowChecked, MF_CHECKED);
\r
8253 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8255 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8256 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8257 MF_BYCOMMAND|MF_ENABLED);
\r
8259 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8260 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8263 prevChecked = nowChecked;
\r
8265 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8266 if (appData.icsActive) {
\r
8267 if (appData.icsEngineAnalyze) {
\r
8268 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8270 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8273 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8279 HMENU hmenu = GetMenu(hwndMain);
\r
8280 SetMenuEnables(hmenu, icsEnables);
\r
8281 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8282 MF_BYCOMMAND|MF_ENABLED);
\r
8284 if (appData.zippyPlay) {
\r
8285 SetMenuEnables(hmenu, zippyEnables);
\r
8286 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8287 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8288 MF_BYCOMMAND|MF_ENABLED);
\r
8296 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8302 HMENU hmenu = GetMenu(hwndMain);
\r
8303 SetMenuEnables(hmenu, ncpEnables);
\r
8304 DrawMenuBar(hwndMain);
\r
8310 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8314 SetTrainingModeOn()
\r
8317 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8318 for (i = 0; i < N_BUTTONS; i++) {
\r
8319 if (buttonDesc[i].hwnd != NULL)
\r
8320 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8325 VOID SetTrainingModeOff()
\r
8328 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8329 for (i = 0; i < N_BUTTONS; i++) {
\r
8330 if (buttonDesc[i].hwnd != NULL)
\r
8331 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8337 SetUserThinkingEnables()
\r
8339 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8343 SetMachineThinkingEnables()
\r
8345 HMENU hMenu = GetMenu(hwndMain);
\r
8346 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8348 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8350 if (gameMode == MachinePlaysBlack) {
\r
8351 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8352 } else if (gameMode == MachinePlaysWhite) {
\r
8353 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8354 } else if (gameMode == TwoMachinesPlay) {
\r
8355 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8361 DisplayTitle(char *str)
\r
8363 char title[MSG_SIZ], *host;
\r
8364 if (str[0] != NULLCHAR) {
\r
8365 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8366 } else if (appData.icsActive) {
\r
8367 if (appData.icsCommPort[0] != NULLCHAR)
\r
8370 host = appData.icsHost;
\r
8371 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8372 } else if (appData.noChessProgram) {
\r
8373 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8375 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8376 strcat(title, ": ");
\r
8377 strcat(title, first.tidy);
\r
8379 SetWindowText(hwndMain, title);
\r
8384 DisplayMessage(char *str1, char *str2)
\r
8388 int remain = MESSAGE_TEXT_MAX - 1;
\r
8391 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8392 messageText[0] = NULLCHAR;
\r
8394 len = strlen(str1);
\r
8395 if (len > remain) len = remain;
\r
8396 strncpy(messageText, str1, len);
\r
8397 messageText[len] = NULLCHAR;
\r
8400 if (*str2 && remain >= 2) {
\r
8402 strcat(messageText, " ");
\r
8405 len = strlen(str2);
\r
8406 if (len > remain) len = remain;
\r
8407 strncat(messageText, str2, len);
\r
8409 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8410 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8412 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8416 hdc = GetDC(hwndMain);
\r
8417 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8418 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8419 &messageRect, messageText, strlen(messageText), NULL);
\r
8420 (void) SelectObject(hdc, oldFont);
\r
8421 (void) ReleaseDC(hwndMain, hdc);
\r
8425 DisplayError(char *str, int error)
\r
8427 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8431 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8433 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8434 NULL, error, LANG_NEUTRAL,
\r
8435 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8437 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8439 ErrorMap *em = errmap;
\r
8440 while (em->err != 0 && em->err != error) em++;
\r
8441 if (em->err != 0) {
\r
8442 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8444 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8449 ErrorPopUp(_("Error"), buf);
\r
8454 DisplayMoveError(char *str)
\r
8456 fromX = fromY = -1;
\r
8457 ClearHighlights();
\r
8458 DrawPosition(FALSE, NULL);
\r
8459 if (appData.popupMoveErrors) {
\r
8460 ErrorPopUp(_("Error"), str);
\r
8462 DisplayMessage(str, "");
\r
8463 moveErrorMessageUp = TRUE;
\r
8468 DisplayFatalError(char *str, int error, int exitStatus)
\r
8470 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8472 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8475 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8476 NULL, error, LANG_NEUTRAL,
\r
8477 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8479 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8481 ErrorMap *em = errmap;
\r
8482 while (em->err != 0 && em->err != error) em++;
\r
8483 if (em->err != 0) {
\r
8484 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8486 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8491 if (appData.debugMode) {
\r
8492 fprintf(debugFP, "%s: %s\n", label, str);
\r
8494 if (appData.popupExitMessage) {
\r
8495 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8496 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8498 ExitEvent(exitStatus);
\r
8503 DisplayInformation(char *str)
\r
8505 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8510 DisplayNote(char *str)
\r
8512 ErrorPopUp(_("Note"), str);
\r
8517 char *title, *question, *replyPrefix;
\r
8522 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8524 static QuestionParams *qp;
\r
8525 char reply[MSG_SIZ];
\r
8528 switch (message) {
\r
8529 case WM_INITDIALOG:
\r
8530 qp = (QuestionParams *) lParam;
\r
8531 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8532 Translate(hDlg, DLG_Question);
\r
8533 SetWindowText(hDlg, qp->title);
\r
8534 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8535 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8539 switch (LOWORD(wParam)) {
\r
8541 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8542 if (*reply) strcat(reply, " ");
\r
8543 len = strlen(reply);
\r
8544 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8545 strcat(reply, "\n");
\r
8546 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8547 EndDialog(hDlg, TRUE);
\r
8548 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8551 EndDialog(hDlg, FALSE);
\r
8562 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8564 QuestionParams qp;
\r
8568 qp.question = question;
\r
8569 qp.replyPrefix = replyPrefix;
\r
8571 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8572 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8573 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8574 FreeProcInstance(lpProc);
\r
8577 /* [AS] Pick FRC position */
\r
8578 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8580 static int * lpIndexFRC;
\r
8586 case WM_INITDIALOG:
\r
8587 lpIndexFRC = (int *) lParam;
\r
8589 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8590 Translate(hDlg, DLG_NewGameFRC);
\r
8592 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8593 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8594 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8595 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8600 switch( LOWORD(wParam) ) {
\r
8602 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8603 EndDialog( hDlg, 0 );
\r
8604 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8607 EndDialog( hDlg, 1 );
\r
8609 case IDC_NFG_Edit:
\r
8610 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8611 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8613 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8616 case IDC_NFG_Random:
\r
8617 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8618 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8631 int index = appData.defaultFrcPosition;
\r
8632 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8634 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8636 if( result == 0 ) {
\r
8637 appData.defaultFrcPosition = index;
\r
8643 /* [AS] Game list options. Refactored by HGM */
\r
8645 HWND gameListOptionsDialog;
\r
8647 // low-level front-end: clear text edit / list widget
\r
8652 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8655 // low-level front-end: clear text edit / list widget
\r
8657 GLT_DeSelectList()
\r
8659 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8662 // low-level front-end: append line to text edit / list widget
\r
8664 GLT_AddToList( char *name )
\r
8667 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8671 // low-level front-end: get line from text edit / list widget
\r
8673 GLT_GetFromList( int index, char *name )
\r
8676 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8682 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8684 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8685 int idx2 = idx1 + delta;
\r
8686 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8688 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8691 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8692 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8693 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8694 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8698 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8702 case WM_INITDIALOG:
\r
8703 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8705 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8706 Translate(hDlg, DLG_GameListOptions);
\r
8708 /* Initialize list */
\r
8709 GLT_TagsToList( lpUserGLT );
\r
8711 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8716 switch( LOWORD(wParam) ) {
\r
8719 EndDialog( hDlg, 0 );
\r
8722 EndDialog( hDlg, 1 );
\r
8725 case IDC_GLT_Default:
\r
8726 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8729 case IDC_GLT_Restore:
\r
8730 GLT_TagsToList( appData.gameListTags );
\r
8734 GLT_MoveSelection( hDlg, -1 );
\r
8737 case IDC_GLT_Down:
\r
8738 GLT_MoveSelection( hDlg, +1 );
\r
8748 int GameListOptions()
\r
8751 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8753 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8755 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8757 if( result == 0 ) {
\r
8758 char *oldTags = appData.gameListTags;
\r
8759 /* [AS] Memory leak here! */
\r
8760 appData.gameListTags = strdup( lpUserGLT );
\r
8761 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8762 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8769 DisplayIcsInteractionTitle(char *str)
\r
8771 char consoleTitle[MSG_SIZ];
\r
8773 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8774 SetWindowText(hwndConsole, consoleTitle);
\r
8776 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8777 char buf[MSG_SIZ], *p = buf, *q;
\r
8778 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8780 q = strchr(p, ';');
\r
8782 if(*p) ChatPopUp(p);
\r
8786 SetActiveWindow(hwndMain);
\r
8790 DrawPosition(int fullRedraw, Board board)
\r
8792 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8795 void NotifyFrontendLogin()
\r
8798 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8804 fromX = fromY = -1;
\r
8805 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8806 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8807 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8808 dragInfo.lastpos = dragInfo.pos;
\r
8809 dragInfo.start.x = dragInfo.start.y = -1;
\r
8810 dragInfo.from = dragInfo.start;
\r
8812 DrawPosition(TRUE, NULL);
\r
8819 CommentPopUp(char *title, char *str)
\r
8821 HWND hwnd = GetActiveWindow();
\r
8822 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8824 SetActiveWindow(hwnd);
\r
8828 CommentPopDown(void)
\r
8830 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8831 if (commentDialog) {
\r
8832 ShowWindow(commentDialog, SW_HIDE);
\r
8834 commentUp = FALSE;
\r
8838 EditCommentPopUp(int index, char *title, char *str)
\r
8840 EitherCommentPopUp(index, title, str, TRUE);
\r
8847 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8854 MyPlaySound(&sounds[(int)SoundMove]);
\r
8857 VOID PlayIcsWinSound()
\r
8859 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8862 VOID PlayIcsLossSound()
\r
8864 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8867 VOID PlayIcsDrawSound()
\r
8869 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8872 VOID PlayIcsUnfinishedSound()
\r
8874 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8880 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8886 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8894 consoleEcho = TRUE;
\r
8895 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8896 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8897 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8906 consoleEcho = FALSE;
\r
8907 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8908 /* This works OK: set text and background both to the same color */
\r
8910 cf.crTextColor = COLOR_ECHOOFF;
\r
8911 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8912 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8915 /* No Raw()...? */
\r
8917 void Colorize(ColorClass cc, int continuation)
\r
8919 currentColorClass = cc;
\r
8920 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8921 consoleCF.crTextColor = textAttribs[cc].color;
\r
8922 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8923 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8929 static char buf[MSG_SIZ];
\r
8930 DWORD bufsiz = MSG_SIZ;
\r
8932 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8933 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8935 if (!GetUserName(buf, &bufsiz)) {
\r
8936 /*DisplayError("Error getting user name", GetLastError());*/
\r
8937 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8945 static char buf[MSG_SIZ];
\r
8946 DWORD bufsiz = MSG_SIZ;
\r
8948 if (!GetComputerName(buf, &bufsiz)) {
\r
8949 /*DisplayError("Error getting host name", GetLastError());*/
\r
8950 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8957 ClockTimerRunning()
\r
8959 return clockTimerEvent != 0;
\r
8965 if (clockTimerEvent == 0) return FALSE;
\r
8966 KillTimer(hwndMain, clockTimerEvent);
\r
8967 clockTimerEvent = 0;
\r
8972 StartClockTimer(long millisec)
\r
8974 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8975 (UINT) millisec, NULL);
\r
8979 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8982 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8984 if(appData.noGUI) return;
\r
8985 hdc = GetDC(hwndMain);
\r
8986 if (!IsIconic(hwndMain)) {
\r
8987 DisplayAClock(hdc, timeRemaining, highlight,
\r
8988 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8990 if (highlight && iconCurrent == iconBlack) {
\r
8991 iconCurrent = iconWhite;
\r
8992 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8993 if (IsIconic(hwndMain)) {
\r
8994 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8997 (void) ReleaseDC(hwndMain, hdc);
\r
8999 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9003 DisplayBlackClock(long timeRemaining, int highlight)
\r
9006 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9009 if(appData.noGUI) return;
\r
9010 hdc = GetDC(hwndMain);
\r
9011 if (!IsIconic(hwndMain)) {
\r
9012 DisplayAClock(hdc, timeRemaining, highlight,
\r
9013 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
9015 if (highlight && iconCurrent == iconWhite) {
\r
9016 iconCurrent = iconBlack;
\r
9017 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9018 if (IsIconic(hwndMain)) {
\r
9019 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9022 (void) ReleaseDC(hwndMain, hdc);
\r
9024 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9029 LoadGameTimerRunning()
\r
9031 return loadGameTimerEvent != 0;
\r
9035 StopLoadGameTimer()
\r
9037 if (loadGameTimerEvent == 0) return FALSE;
\r
9038 KillTimer(hwndMain, loadGameTimerEvent);
\r
9039 loadGameTimerEvent = 0;
\r
9044 StartLoadGameTimer(long millisec)
\r
9046 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9047 (UINT) millisec, NULL);
\r
9055 char fileTitle[MSG_SIZ];
\r
9057 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9058 f = OpenFileDialog(hwndMain, "a", defName,
\r
9059 appData.oldSaveStyle ? "gam" : "pgn",
\r
9061 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9063 SaveGame(f, 0, "");
\r
9070 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9072 if (delayedTimerEvent != 0) {
\r
9073 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9074 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9076 KillTimer(hwndMain, delayedTimerEvent);
\r
9077 delayedTimerEvent = 0;
\r
9078 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9079 delayedTimerCallback();
\r
9081 delayedTimerCallback = cb;
\r
9082 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9083 (UINT) millisec, NULL);
\r
9086 DelayedEventCallback
\r
9089 if (delayedTimerEvent) {
\r
9090 return delayedTimerCallback;
\r
9097 CancelDelayedEvent()
\r
9099 if (delayedTimerEvent) {
\r
9100 KillTimer(hwndMain, delayedTimerEvent);
\r
9101 delayedTimerEvent = 0;
\r
9105 DWORD GetWin32Priority(int nice)
\r
9106 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9108 REALTIME_PRIORITY_CLASS 0x00000100
\r
9109 HIGH_PRIORITY_CLASS 0x00000080
\r
9110 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9111 NORMAL_PRIORITY_CLASS 0x00000020
\r
9112 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9113 IDLE_PRIORITY_CLASS 0x00000040
\r
9115 if (nice < -15) return 0x00000080;
\r
9116 if (nice < 0) return 0x00008000;
\r
9117 if (nice == 0) return 0x00000020;
\r
9118 if (nice < 15) return 0x00004000;
\r
9119 return 0x00000040;
\r
9122 void RunCommand(char *cmdLine)
\r
9124 /* Now create the child process. */
\r
9125 STARTUPINFO siStartInfo;
\r
9126 PROCESS_INFORMATION piProcInfo;
\r
9128 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9129 siStartInfo.lpReserved = NULL;
\r
9130 siStartInfo.lpDesktop = NULL;
\r
9131 siStartInfo.lpTitle = NULL;
\r
9132 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9133 siStartInfo.cbReserved2 = 0;
\r
9134 siStartInfo.lpReserved2 = NULL;
\r
9135 siStartInfo.hStdInput = NULL;
\r
9136 siStartInfo.hStdOutput = NULL;
\r
9137 siStartInfo.hStdError = NULL;
\r
9139 CreateProcess(NULL,
\r
9140 cmdLine, /* command line */
\r
9141 NULL, /* process security attributes */
\r
9142 NULL, /* primary thread security attrs */
\r
9143 TRUE, /* handles are inherited */
\r
9144 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9145 NULL, /* use parent's environment */
\r
9147 &siStartInfo, /* STARTUPINFO pointer */
\r
9148 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9150 CloseHandle(piProcInfo.hThread);
\r
9153 /* Start a child process running the given program.
\r
9154 The process's standard output can be read from "from", and its
\r
9155 standard input can be written to "to".
\r
9156 Exit with fatal error if anything goes wrong.
\r
9157 Returns an opaque pointer that can be used to destroy the process
\r
9161 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9163 #define BUFSIZE 4096
\r
9165 HANDLE hChildStdinRd, hChildStdinWr,
\r
9166 hChildStdoutRd, hChildStdoutWr;
\r
9167 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9168 SECURITY_ATTRIBUTES saAttr;
\r
9170 PROCESS_INFORMATION piProcInfo;
\r
9171 STARTUPINFO siStartInfo;
\r
9173 char buf[MSG_SIZ];
\r
9176 if (appData.debugMode) {
\r
9177 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9182 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9183 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9184 saAttr.bInheritHandle = TRUE;
\r
9185 saAttr.lpSecurityDescriptor = NULL;
\r
9188 * The steps for redirecting child's STDOUT:
\r
9189 * 1. Create anonymous pipe to be STDOUT for child.
\r
9190 * 2. Create a noninheritable duplicate of read handle,
\r
9191 * and close the inheritable read handle.
\r
9194 /* Create a pipe for the child's STDOUT. */
\r
9195 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9196 return GetLastError();
\r
9199 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9200 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9201 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9202 FALSE, /* not inherited */
\r
9203 DUPLICATE_SAME_ACCESS);
\r
9205 return GetLastError();
\r
9207 CloseHandle(hChildStdoutRd);
\r
9210 * The steps for redirecting child's STDIN:
\r
9211 * 1. Create anonymous pipe to be STDIN for child.
\r
9212 * 2. Create a noninheritable duplicate of write handle,
\r
9213 * and close the inheritable write handle.
\r
9216 /* Create a pipe for the child's STDIN. */
\r
9217 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9218 return GetLastError();
\r
9221 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9222 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9223 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9224 FALSE, /* not inherited */
\r
9225 DUPLICATE_SAME_ACCESS);
\r
9227 return GetLastError();
\r
9229 CloseHandle(hChildStdinWr);
\r
9231 /* Arrange to (1) look in dir for the child .exe file, and
\r
9232 * (2) have dir be the child's working directory. Interpret
\r
9233 * dir relative to the directory WinBoard loaded from. */
\r
9234 GetCurrentDirectory(MSG_SIZ, buf);
\r
9235 SetCurrentDirectory(installDir);
\r
9236 SetCurrentDirectory(dir);
\r
9238 /* Now create the child process. */
\r
9240 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9241 siStartInfo.lpReserved = NULL;
\r
9242 siStartInfo.lpDesktop = NULL;
\r
9243 siStartInfo.lpTitle = NULL;
\r
9244 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9245 siStartInfo.cbReserved2 = 0;
\r
9246 siStartInfo.lpReserved2 = NULL;
\r
9247 siStartInfo.hStdInput = hChildStdinRd;
\r
9248 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9249 siStartInfo.hStdError = hChildStdoutWr;
\r
9251 fSuccess = CreateProcess(NULL,
\r
9252 cmdLine, /* command line */
\r
9253 NULL, /* process security attributes */
\r
9254 NULL, /* primary thread security attrs */
\r
9255 TRUE, /* handles are inherited */
\r
9256 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9257 NULL, /* use parent's environment */
\r
9259 &siStartInfo, /* STARTUPINFO pointer */
\r
9260 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9262 err = GetLastError();
\r
9263 SetCurrentDirectory(buf); /* return to prev directory */
\r
9268 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9269 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9270 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9273 /* Close the handles we don't need in the parent */
\r
9274 CloseHandle(piProcInfo.hThread);
\r
9275 CloseHandle(hChildStdinRd);
\r
9276 CloseHandle(hChildStdoutWr);
\r
9278 /* Prepare return value */
\r
9279 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9280 cp->kind = CPReal;
\r
9281 cp->hProcess = piProcInfo.hProcess;
\r
9282 cp->pid = piProcInfo.dwProcessId;
\r
9283 cp->hFrom = hChildStdoutRdDup;
\r
9284 cp->hTo = hChildStdinWrDup;
\r
9286 *pr = (void *) cp;
\r
9288 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9289 2000 where engines sometimes don't see the initial command(s)
\r
9290 from WinBoard and hang. I don't understand how that can happen,
\r
9291 but the Sleep is harmless, so I've put it in. Others have also
\r
9292 reported what may be the same problem, so hopefully this will fix
\r
9293 it for them too. */
\r
9301 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9303 ChildProc *cp; int result;
\r
9305 cp = (ChildProc *) pr;
\r
9306 if (cp == NULL) return;
\r
9308 switch (cp->kind) {
\r
9310 /* TerminateProcess is considered harmful, so... */
\r
9311 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9312 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9313 /* The following doesn't work because the chess program
\r
9314 doesn't "have the same console" as WinBoard. Maybe
\r
9315 we could arrange for this even though neither WinBoard
\r
9316 nor the chess program uses a console for stdio? */
\r
9317 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9319 /* [AS] Special termination modes for misbehaving programs... */
\r
9320 if( signal & 8 ) {
\r
9321 result = TerminateProcess( cp->hProcess, 0 );
\r
9323 if ( appData.debugMode) {
\r
9324 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9327 else if( signal & 4 ) {
\r
9328 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9330 if( dw != WAIT_OBJECT_0 ) {
\r
9331 result = TerminateProcess( cp->hProcess, 0 );
\r
9333 if ( appData.debugMode) {
\r
9334 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9340 CloseHandle(cp->hProcess);
\r
9344 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9348 closesocket(cp->sock);
\r
9353 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9354 closesocket(cp->sock);
\r
9355 closesocket(cp->sock2);
\r
9363 InterruptChildProcess(ProcRef pr)
\r
9367 cp = (ChildProc *) pr;
\r
9368 if (cp == NULL) return;
\r
9369 switch (cp->kind) {
\r
9371 /* The following doesn't work because the chess program
\r
9372 doesn't "have the same console" as WinBoard. Maybe
\r
9373 we could arrange for this even though neither WinBoard
\r
9374 nor the chess program uses a console for stdio */
\r
9375 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9380 /* Can't interrupt */
\r
9384 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9391 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9393 char cmdLine[MSG_SIZ];
\r
9395 if (port[0] == NULLCHAR) {
\r
9396 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9398 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9400 return StartChildProcess(cmdLine, "", pr);
\r
9404 /* Code to open TCP sockets */
\r
9407 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9413 struct sockaddr_in sa, mysa;
\r
9414 struct hostent FAR *hp;
\r
9415 unsigned short uport;
\r
9416 WORD wVersionRequested;
\r
9419 /* Initialize socket DLL */
\r
9420 wVersionRequested = MAKEWORD(1, 1);
\r
9421 err = WSAStartup(wVersionRequested, &wsaData);
\r
9422 if (err != 0) return err;
\r
9425 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9426 err = WSAGetLastError();
\r
9431 /* Bind local address using (mostly) don't-care values.
\r
9433 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9434 mysa.sin_family = AF_INET;
\r
9435 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9436 uport = (unsigned short) 0;
\r
9437 mysa.sin_port = htons(uport);
\r
9438 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9439 == SOCKET_ERROR) {
\r
9440 err = WSAGetLastError();
\r
9445 /* Resolve remote host name */
\r
9446 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9447 if (!(hp = gethostbyname(host))) {
\r
9448 unsigned int b0, b1, b2, b3;
\r
9450 err = WSAGetLastError();
\r
9452 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9453 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9454 hp->h_addrtype = AF_INET;
\r
9456 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9457 hp->h_addr_list[0] = (char *) malloc(4);
\r
9458 hp->h_addr_list[0][0] = (char) b0;
\r
9459 hp->h_addr_list[0][1] = (char) b1;
\r
9460 hp->h_addr_list[0][2] = (char) b2;
\r
9461 hp->h_addr_list[0][3] = (char) b3;
\r
9467 sa.sin_family = hp->h_addrtype;
\r
9468 uport = (unsigned short) atoi(port);
\r
9469 sa.sin_port = htons(uport);
\r
9470 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9472 /* Make connection */
\r
9473 if (connect(s, (struct sockaddr *) &sa,
\r
9474 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9475 err = WSAGetLastError();
\r
9480 /* Prepare return value */
\r
9481 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9482 cp->kind = CPSock;
\r
9484 *pr = (ProcRef *) cp;
\r
9490 OpenCommPort(char *name, ProcRef *pr)
\r
9495 char fullname[MSG_SIZ];
\r
9497 if (*name != '\\')
\r
9498 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9500 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9502 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9503 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9504 if (h == (HANDLE) -1) {
\r
9505 return GetLastError();
\r
9509 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9511 /* Accumulate characters until a 100ms pause, then parse */
\r
9512 ct.ReadIntervalTimeout = 100;
\r
9513 ct.ReadTotalTimeoutMultiplier = 0;
\r
9514 ct.ReadTotalTimeoutConstant = 0;
\r
9515 ct.WriteTotalTimeoutMultiplier = 0;
\r
9516 ct.WriteTotalTimeoutConstant = 0;
\r
9517 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9519 /* Prepare return value */
\r
9520 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9521 cp->kind = CPComm;
\r
9524 *pr = (ProcRef *) cp;
\r
9530 OpenLoopback(ProcRef *pr)
\r
9532 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9538 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9543 struct sockaddr_in sa, mysa;
\r
9544 struct hostent FAR *hp;
\r
9545 unsigned short uport;
\r
9546 WORD wVersionRequested;
\r
9549 char stderrPortStr[MSG_SIZ];
\r
9551 /* Initialize socket DLL */
\r
9552 wVersionRequested = MAKEWORD(1, 1);
\r
9553 err = WSAStartup(wVersionRequested, &wsaData);
\r
9554 if (err != 0) return err;
\r
9556 /* Resolve remote host name */
\r
9557 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9558 if (!(hp = gethostbyname(host))) {
\r
9559 unsigned int b0, b1, b2, b3;
\r
9561 err = WSAGetLastError();
\r
9563 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9564 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9565 hp->h_addrtype = AF_INET;
\r
9567 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9568 hp->h_addr_list[0] = (char *) malloc(4);
\r
9569 hp->h_addr_list[0][0] = (char) b0;
\r
9570 hp->h_addr_list[0][1] = (char) b1;
\r
9571 hp->h_addr_list[0][2] = (char) b2;
\r
9572 hp->h_addr_list[0][3] = (char) b3;
\r
9578 sa.sin_family = hp->h_addrtype;
\r
9579 uport = (unsigned short) 514;
\r
9580 sa.sin_port = htons(uport);
\r
9581 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9583 /* Bind local socket to unused "privileged" port address
\r
9585 s = INVALID_SOCKET;
\r
9586 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9587 mysa.sin_family = AF_INET;
\r
9588 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9589 for (fromPort = 1023;; fromPort--) {
\r
9590 if (fromPort < 0) {
\r
9592 return WSAEADDRINUSE;
\r
9594 if (s == INVALID_SOCKET) {
\r
9595 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9596 err = WSAGetLastError();
\r
9601 uport = (unsigned short) fromPort;
\r
9602 mysa.sin_port = htons(uport);
\r
9603 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9604 == SOCKET_ERROR) {
\r
9605 err = WSAGetLastError();
\r
9606 if (err == WSAEADDRINUSE) continue;
\r
9610 if (connect(s, (struct sockaddr *) &sa,
\r
9611 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9612 err = WSAGetLastError();
\r
9613 if (err == WSAEADDRINUSE) {
\r
9624 /* Bind stderr local socket to unused "privileged" port address
\r
9626 s2 = INVALID_SOCKET;
\r
9627 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9628 mysa.sin_family = AF_INET;
\r
9629 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9630 for (fromPort = 1023;; fromPort--) {
\r
9631 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9632 if (fromPort < 0) {
\r
9633 (void) closesocket(s);
\r
9635 return WSAEADDRINUSE;
\r
9637 if (s2 == INVALID_SOCKET) {
\r
9638 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9639 err = WSAGetLastError();
\r
9645 uport = (unsigned short) fromPort;
\r
9646 mysa.sin_port = htons(uport);
\r
9647 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9648 == SOCKET_ERROR) {
\r
9649 err = WSAGetLastError();
\r
9650 if (err == WSAEADDRINUSE) continue;
\r
9651 (void) closesocket(s);
\r
9655 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9656 err = WSAGetLastError();
\r
9657 if (err == WSAEADDRINUSE) {
\r
9659 s2 = INVALID_SOCKET;
\r
9662 (void) closesocket(s);
\r
9663 (void) closesocket(s2);
\r
9669 prevStderrPort = fromPort; // remember port used
\r
9670 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9672 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9673 err = WSAGetLastError();
\r
9674 (void) closesocket(s);
\r
9675 (void) closesocket(s2);
\r
9680 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9681 err = WSAGetLastError();
\r
9682 (void) closesocket(s);
\r
9683 (void) closesocket(s2);
\r
9687 if (*user == NULLCHAR) user = UserName();
\r
9688 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9689 err = WSAGetLastError();
\r
9690 (void) closesocket(s);
\r
9691 (void) closesocket(s2);
\r
9695 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9696 err = WSAGetLastError();
\r
9697 (void) closesocket(s);
\r
9698 (void) closesocket(s2);
\r
9703 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9704 err = WSAGetLastError();
\r
9705 (void) closesocket(s);
\r
9706 (void) closesocket(s2);
\r
9710 (void) closesocket(s2); /* Stop listening */
\r
9712 /* Prepare return value */
\r
9713 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9714 cp->kind = CPRcmd;
\r
9717 *pr = (ProcRef *) cp;
\r
9724 AddInputSource(ProcRef pr, int lineByLine,
\r
9725 InputCallback func, VOIDSTAR closure)
\r
9727 InputSource *is, *is2 = NULL;
\r
9728 ChildProc *cp = (ChildProc *) pr;
\r
9730 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9731 is->lineByLine = lineByLine;
\r
9733 is->closure = closure;
\r
9734 is->second = NULL;
\r
9735 is->next = is->buf;
\r
9736 if (pr == NoProc) {
\r
9737 is->kind = CPReal;
\r
9738 consoleInputSource = is;
\r
9740 is->kind = cp->kind;
\r
9742 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9743 we create all threads suspended so that the is->hThread variable can be
\r
9744 safely assigned, then let the threads start with ResumeThread.
\r
9746 switch (cp->kind) {
\r
9748 is->hFile = cp->hFrom;
\r
9749 cp->hFrom = NULL; /* now owned by InputThread */
\r
9751 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9752 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9756 is->hFile = cp->hFrom;
\r
9757 cp->hFrom = NULL; /* now owned by InputThread */
\r
9759 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9760 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9764 is->sock = cp->sock;
\r
9766 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9767 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9771 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9773 is->sock = cp->sock;
\r
9775 is2->sock = cp->sock2;
\r
9776 is2->second = is2;
\r
9778 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9779 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9781 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9782 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9786 if( is->hThread != NULL ) {
\r
9787 ResumeThread( is->hThread );
\r
9790 if( is2 != NULL && is2->hThread != NULL ) {
\r
9791 ResumeThread( is2->hThread );
\r
9795 return (InputSourceRef) is;
\r
9799 RemoveInputSource(InputSourceRef isr)
\r
9803 is = (InputSource *) isr;
\r
9804 is->hThread = NULL; /* tell thread to stop */
\r
9805 CloseHandle(is->hThread);
\r
9806 if (is->second != NULL) {
\r
9807 is->second->hThread = NULL;
\r
9808 CloseHandle(is->second->hThread);
\r
9812 int no_wrap(char *message, int count)
\r
9814 ConsoleOutput(message, count, FALSE);
\r
9819 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9822 int outCount = SOCKET_ERROR;
\r
9823 ChildProc *cp = (ChildProc *) pr;
\r
9824 static OVERLAPPED ovl;
\r
9826 static int line = 0;
\r
9830 if (appData.noJoin || !appData.useInternalWrap)
\r
9831 return no_wrap(message, count);
\r
9834 int width = get_term_width();
\r
9835 int len = wrap(NULL, message, count, width, &line);
\r
9836 char *msg = malloc(len);
\r
9840 return no_wrap(message, count);
\r
9843 dbgchk = wrap(msg, message, count, width, &line);
\r
9844 if (dbgchk != len && appData.debugMode)
\r
9845 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9846 ConsoleOutput(msg, len, FALSE);
\r
9853 if (ovl.hEvent == NULL) {
\r
9854 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9856 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9858 switch (cp->kind) {
\r
9861 outCount = send(cp->sock, message, count, 0);
\r
9862 if (outCount == SOCKET_ERROR) {
\r
9863 *outError = WSAGetLastError();
\r
9865 *outError = NO_ERROR;
\r
9870 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9871 &dOutCount, NULL)) {
\r
9872 *outError = NO_ERROR;
\r
9873 outCount = (int) dOutCount;
\r
9875 *outError = GetLastError();
\r
9880 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9881 &dOutCount, &ovl);
\r
9882 if (*outError == NO_ERROR) {
\r
9883 outCount = (int) dOutCount;
\r
9893 if(n != 0) Sleep(n);
\r
9897 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9900 /* Ignore delay, not implemented for WinBoard */
\r
9901 return OutputToProcess(pr, message, count, outError);
\r
9906 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9907 char *buf, int count, int error)
\r
9909 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9912 /* see wgamelist.c for Game List functions */
\r
9913 /* see wedittags.c for Edit Tags functions */
\r
9920 char buf[MSG_SIZ];
\r
9923 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9924 f = fopen(buf, "r");
\r
9926 ProcessICSInitScript(f);
\r
9936 StartAnalysisClock()
\r
9938 if (analysisTimerEvent) return;
\r
9939 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9940 (UINT) 2000, NULL);
\r
9944 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9946 highlightInfo.sq[0].x = fromX;
\r
9947 highlightInfo.sq[0].y = fromY;
\r
9948 highlightInfo.sq[1].x = toX;
\r
9949 highlightInfo.sq[1].y = toY;
\r
9955 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9956 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9960 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9962 premoveHighlightInfo.sq[0].x = fromX;
\r
9963 premoveHighlightInfo.sq[0].y = fromY;
\r
9964 premoveHighlightInfo.sq[1].x = toX;
\r
9965 premoveHighlightInfo.sq[1].y = toY;
\r
9969 ClearPremoveHighlights()
\r
9971 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9972 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9976 ShutDownFrontEnd()
\r
9978 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9979 DeleteClipboardTempFiles();
\r
9985 if (IsIconic(hwndMain))
\r
9986 ShowWindow(hwndMain, SW_RESTORE);
\r
9988 SetActiveWindow(hwndMain);
\r
9992 * Prototypes for animation support routines
\r
9994 static void ScreenSquare(int column, int row, POINT * pt);
\r
9995 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9996 POINT frames[], int * nFrames);
\r
10002 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
10003 { // [HGM] atomic: animate blast wave
\r
10006 explodeInfo.fromX = fromX;
\r
10007 explodeInfo.fromY = fromY;
\r
10008 explodeInfo.toX = toX;
\r
10009 explodeInfo.toY = toY;
\r
10010 for(i=1; i<4*kFactor; i++) {
\r
10011 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
10012 DrawPosition(FALSE, board);
\r
10013 Sleep(appData.animSpeed);
\r
10015 explodeInfo.radius = 0;
\r
10016 DrawPosition(TRUE, board);
\r
10020 AnimateMove(board, fromX, fromY, toX, toY)
\r
10027 ChessSquare piece;
\r
10028 int x = toX, y = toY;
\r
10029 POINT start, finish, mid;
\r
10030 POINT frames[kFactor * 2 + 1];
\r
10033 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
10035 if (!appData.animate) return;
\r
10036 if (doingSizing) return;
\r
10037 if (fromY < 0 || fromX < 0) return;
\r
10038 piece = board[fromY][fromX];
\r
10039 if (piece >= EmptySquare) return;
\r
10041 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10045 ScreenSquare(fromX, fromY, &start);
\r
10046 ScreenSquare(toX, toY, &finish);
\r
10048 /* All moves except knight jumps move in straight line */
\r
10049 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10050 mid.x = start.x + (finish.x - start.x) / 2;
\r
10051 mid.y = start.y + (finish.y - start.y) / 2;
\r
10053 /* Knight: make straight movement then diagonal */
\r
10054 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10055 mid.x = start.x + (finish.x - start.x) / 2;
\r
10059 mid.y = start.y + (finish.y - start.y) / 2;
\r
10063 /* Don't use as many frames for very short moves */
\r
10064 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10065 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10067 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10069 animInfo.from.x = fromX;
\r
10070 animInfo.from.y = fromY;
\r
10071 animInfo.to.x = toX;
\r
10072 animInfo.to.y = toY;
\r
10073 animInfo.lastpos = start;
\r
10074 animInfo.piece = piece;
\r
10075 for (n = 0; n < nFrames; n++) {
\r
10076 animInfo.pos = frames[n];
\r
10077 DrawPosition(FALSE, NULL);
\r
10078 animInfo.lastpos = animInfo.pos;
\r
10079 Sleep(appData.animSpeed);
\r
10081 animInfo.pos = finish;
\r
10082 DrawPosition(FALSE, NULL);
\r
10084 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10086 animInfo.piece = EmptySquare;
\r
10087 Explode(board, fromX, fromY, toX, toY);
\r
10090 /* Convert board position to corner of screen rect and color */
\r
10093 ScreenSquare(column, row, pt)
\r
10094 int column; int row; POINT * pt;
\r
10097 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10098 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10100 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10101 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10105 /* Generate a series of frame coords from start->mid->finish.
\r
10106 The movement rate doubles until the half way point is
\r
10107 reached, then halves back down to the final destination,
\r
10108 which gives a nice slow in/out effect. The algorithmn
\r
10109 may seem to generate too many intermediates for short
\r
10110 moves, but remember that the purpose is to attract the
\r
10111 viewers attention to the piece about to be moved and
\r
10112 then to where it ends up. Too few frames would be less
\r
10116 Tween(start, mid, finish, factor, frames, nFrames)
\r
10117 POINT * start; POINT * mid;
\r
10118 POINT * finish; int factor;
\r
10119 POINT frames[]; int * nFrames;
\r
10121 int n, fraction = 1, count = 0;
\r
10123 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10124 for (n = 0; n < factor; n++)
\r
10126 for (n = 0; n < factor; n++) {
\r
10127 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10128 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10130 fraction = fraction / 2;
\r
10134 frames[count] = *mid;
\r
10137 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10139 for (n = 0; n < factor; n++) {
\r
10140 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10141 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10143 fraction = fraction * 2;
\r
10145 *nFrames = count;
\r
10149 SettingsPopUp(ChessProgramState *cps)
\r
10150 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10151 EngineOptionsPopup(savedHwnd, cps);
\r
10154 int flock(int fid, int code)
\r
10156 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10158 ov.hEvent = NULL;
\r
10160 ov.OffsetHigh = 0;
\r
10162 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10164 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10165 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10166 default: return -1;
\r
10175 static char col[8][20];
\r
10176 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10178 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10183 ActivateTheme (int new)
\r
10184 { // Redo initialization of features depending on options that can occur in themes
\r
10186 if(new) InitDrawingColors();
\r
10187 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10188 InitDrawingSizes(boardSize, 0);
\r
10189 InvalidateRect(hwndMain, NULL, TRUE);
\r