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
1110 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
1112 HWND hwnd; /* Main window handle. */
\r
1114 WINDOWPLACEMENT wp;
\r
1117 hInst = hInstance; /* Store instance handle in our global variable */
\r
1118 programName = szAppName;
\r
1120 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
1121 *filepart = NULLCHAR;
\r
1122 SetCurrentDirectory(installDir);
\r
1124 GetCurrentDirectory(MSG_SIZ, installDir);
\r
1126 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
1128 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
1129 /* xboard, and older WinBoards, controlled the move sound with the
\r
1130 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1131 always turn the option on (so that the backend will call us),
\r
1132 then let the user turn the sound off by setting it to silence if
\r
1133 desired. To accommodate old winboard.ini files saved by old
\r
1134 versions of WinBoard, we also turn off the sound if the option
\r
1135 was initially set to false. [HGM] taken out of InitAppData */
\r
1136 if (!appData.ringBellAfterMoves) {
\r
1137 sounds[(int)SoundMove].name = strdup("");
\r
1138 appData.ringBellAfterMoves = TRUE;
\r
1140 if (appData.debugMode) {
\r
1141 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
1142 setbuf(debugFP, NULL);
\r
1145 LoadLanguageFile(appData.language);
\r
1149 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
1150 // InitEngineUCI( installDir, &second );
\r
1152 /* Create a main window for this application instance. */
\r
1153 hwnd = CreateWindow(szAppName, szTitle,
\r
1154 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
1155 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
1156 NULL, NULL, hInstance, NULL);
\r
1159 /* If window could not be created, return "failure" */
\r
1164 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
1165 LoadLogo(&first, 0, FALSE);
\r
1166 LoadLogo(&second, 1, appData.icsActive);
\r
1170 iconWhite = LoadIcon(hInstance, "icon_white");
\r
1171 iconBlack = LoadIcon(hInstance, "icon_black");
\r
1172 iconCurrent = iconWhite;
\r
1173 InitDrawingColors();
\r
1175 InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args
\r
1176 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
1177 /* Compute window size for each board size, and use the largest
\r
1178 size that fits on this screen as the default. */
\r
1179 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
1180 if (boardSize == (BoardSize)-1 &&
\r
1181 winH <= screenHeight
\r
1182 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
1183 && winW <= screenWidth) {
\r
1184 boardSize = (BoardSize)ibs;
\r
1188 InitDrawingSizes(boardSize, 0);
\r
1189 RecentEngineMenu(appData.recentEngineList);
\r
1191 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
1193 /* [AS] Load textures if specified */
\r
1196 mysrandom( (unsigned) time(NULL) );
\r
1198 /* [AS] Restore layout */
\r
1199 if( wpMoveHistory.visible ) {
\r
1200 MoveHistoryPopUp();
\r
1203 if( wpEvalGraph.visible ) {
\r
1207 if( wpEngineOutput.visible ) {
\r
1208 EngineOutputPopUp();
\r
1211 /* Make the window visible; update its client area; and return "success" */
\r
1212 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1213 wp.length = sizeof(WINDOWPLACEMENT);
\r
1215 wp.showCmd = nCmdShow;
\r
1216 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
1217 wp.rcNormalPosition.left = wpMain.x;
\r
1218 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
1219 wp.rcNormalPosition.top = wpMain.y;
\r
1220 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
1221 SetWindowPlacement(hwndMain, &wp);
\r
1223 InitBackEnd2(); // [HGM] moved until after all windows placed, to save correct position if fatal error on engine start
\r
1225 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1226 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1228 if (hwndConsole) {
\r
1230 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
1231 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
1233 ShowWindow(hwndConsole, nCmdShow);
\r
1234 SetActiveWindow(hwndConsole);
\r
1236 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
1237 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
1246 HMENU hmenu = GetMenu(hwndMain);
\r
1248 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
1249 MF_BYCOMMAND|((appData.icsActive &&
\r
1250 *appData.icsCommPort != NULLCHAR) ?
\r
1251 MF_ENABLED : MF_GRAYED));
\r
1252 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
1253 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
1254 MF_CHECKED : MF_UNCHECKED));
\r
1255 EnableMenuItem(hmenu, IDM_SaveSelected, MF_GRAYED);
\r
1258 //---------------------------------------------------------------------------------------------------------
\r
1260 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
1261 #define XBOARD FALSE
\r
1263 #define OPTCHAR "/"
\r
1264 #define SEPCHAR "="
\r
1265 #define TOPLEVEL 0
\r
1269 // front-end part of option handling
\r
1272 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1274 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1275 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1278 lf->lfEscapement = 0;
\r
1279 lf->lfOrientation = 0;
\r
1280 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1281 lf->lfItalic = mfp->italic;
\r
1282 lf->lfUnderline = mfp->underline;
\r
1283 lf->lfStrikeOut = mfp->strikeout;
\r
1284 lf->lfCharSet = mfp->charset;
\r
1285 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1289 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1290 lf->lfQuality = DEFAULT_QUALITY;
\r
1291 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1292 safeStrCpy(lf->lfFaceName, mfp->faceName, sizeof(lf->lfFaceName)/sizeof(lf->lfFaceName[0]) );
\r
1296 CreateFontInMF(MyFont *mf)
\r
1298 LFfromMFP(&mf->lf, &mf->mfp);
\r
1299 if (mf->hf) DeleteObject(mf->hf);
\r
1300 mf->hf = CreateFontIndirect(&mf->lf);
\r
1303 // [HGM] This platform-dependent table provides the location for storing the color info
\r
1305 colorVariable[] = {
\r
1306 &whitePieceColor,
\r
1307 &blackPieceColor,
\r
1308 &lightSquareColor,
\r
1309 &darkSquareColor,
\r
1310 &highlightSquareColor,
\r
1311 &premoveHighlightColor,
\r
1313 &consoleBackgroundColor,
\r
1314 &appData.fontForeColorWhite,
\r
1315 &appData.fontBackColorWhite,
\r
1316 &appData.fontForeColorBlack,
\r
1317 &appData.fontBackColorBlack,
\r
1318 &appData.evalHistColorWhite,
\r
1319 &appData.evalHistColorBlack,
\r
1320 &appData.highlightArrowColor,
\r
1323 /* Command line font name parser. NULL name means do nothing.
\r
1324 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1325 For backward compatibility, syntax without the colon is also
\r
1326 accepted, but font names with digits in them won't work in that case.
\r
1329 ParseFontName(char *name, MyFontParams *mfp)
\r
1332 if (name == NULL) return;
\r
1334 q = strchr(p, ':');
\r
1336 if (q - p >= sizeof(mfp->faceName))
\r
1337 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1338 memcpy(mfp->faceName, p, q - p);
\r
1339 mfp->faceName[q - p] = NULLCHAR;
\r
1342 q = mfp->faceName;
\r
1344 while (*p && !isdigit(*p)) {
\r
1346 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1347 ExitArgError(_("Font name too long:"), name, TRUE);
\r
1349 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1352 if (!*p) ExitArgError(_("Font point size missing:"), name, TRUE);
\r
1353 mfp->pointSize = (float) atof(p);
\r
1354 mfp->bold = (strchr(p, 'b') != NULL);
\r
1355 mfp->italic = (strchr(p, 'i') != NULL);
\r
1356 mfp->underline = (strchr(p, 'u') != NULL);
\r
1357 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1358 mfp->charset = DEFAULT_CHARSET;
\r
1359 q = strchr(p, 'c');
\r
1361 mfp->charset = (BYTE) atoi(q+1);
\r
1365 ParseFont(char *name, int number)
\r
1366 { // wrapper to shield back-end from 'font'
\r
1367 ParseFontName(name, &font[boardSize][number]->mfp);
\r
1372 { // in WB we have a 2D array of fonts; this initializes their description
\r
1374 /* Point font array elements to structures and
\r
1375 parse default font names */
\r
1376 for (i=0; i<NUM_FONTS; i++) {
\r
1377 for (j=0; j<NUM_SIZES; j++) {
\r
1378 font[j][i] = &fontRec[j][i];
\r
1379 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1386 { // here we create the actual fonts from the selected descriptions
\r
1388 for (i=0; i<NUM_FONTS; i++) {
\r
1389 for (j=0; j<NUM_SIZES; j++) {
\r
1390 CreateFontInMF(font[j][i]);
\r
1394 /* Color name parser.
\r
1395 X version accepts X color names, but this one
\r
1396 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1398 ParseColorName(char *name)
\r
1400 int red, green, blue, count;
\r
1401 char buf[MSG_SIZ];
\r
1403 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1405 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1406 &red, &green, &blue);
\r
1409 snprintf(buf, MSG_SIZ, _("Can't parse color name %s"), name);
\r
1410 DisplayError(buf, 0);
\r
1411 return RGB(0, 0, 0);
\r
1413 return PALETTERGB(red, green, blue);
\r
1417 ParseColor(int n, char *name)
\r
1418 { // for WinBoard the color is an int, which needs to be derived from the string
\r
1419 if(colorVariable[n]) *(int*)colorVariable[n] = ParseColorName(name);
\r
1423 ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1425 char *e = argValue;
\r
1429 if (*e == 'b') eff |= CFE_BOLD;
\r
1430 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1431 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1432 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1433 else if (*e == '#' || isdigit(*e)) break;
\r
1437 *color = ParseColorName(e);
\r
1441 ParseTextAttribs(ColorClass cc, char *s)
\r
1442 { // [HGM] front-end wrapper that does the platform-dependent call
\r
1443 // for XBoard we would set (&appData.colorShout)[cc] = strdup(s);
\r
1444 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, s);
\r
1448 ParseBoardSize(void *addr, char *name)
\r
1449 { // [HGM] rewritten with return-value ptr to shield back-end from BoardSize
\r
1450 BoardSize bs = SizeTiny;
\r
1451 while (sizeInfo[bs].name != NULL) {
\r
1452 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) {
\r
1453 *(BoardSize *)addr = bs;
\r
1458 ExitArgError(_("Unrecognized board size value"), name, TRUE);
\r
1463 { // [HGM] import name from appData first
\r
1466 for (cc = (ColorClass)0; cc < ColorNormal; cc++) {
\r
1467 textAttribs[cc].sound.name = strdup((&appData.soundShout)[cc]);
\r
1468 textAttribs[cc].sound.data = NULL;
\r
1469 MyLoadSound(&textAttribs[cc].sound);
\r
1471 for (cc = ColorNormal; cc < NColorClasses; cc++) {
\r
1472 textAttribs[cc].sound.name = strdup("");
\r
1473 textAttribs[cc].sound.data = NULL;
\r
1475 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1476 sounds[sc].name = strdup((&appData.soundMove)[sc]);
\r
1477 sounds[sc].data = NULL;
\r
1478 MyLoadSound(&sounds[sc]);
\r
1483 SetCommPortDefaults()
\r
1485 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1486 dcb.DCBlength = sizeof(DCB);
\r
1487 dcb.BaudRate = 9600;
\r
1488 dcb.fBinary = TRUE;
\r
1489 dcb.fParity = FALSE;
\r
1490 dcb.fOutxCtsFlow = FALSE;
\r
1491 dcb.fOutxDsrFlow = FALSE;
\r
1492 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1493 dcb.fDsrSensitivity = FALSE;
\r
1494 dcb.fTXContinueOnXoff = TRUE;
\r
1495 dcb.fOutX = FALSE;
\r
1497 dcb.fNull = FALSE;
\r
1498 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1499 dcb.fAbortOnError = FALSE;
\r
1501 dcb.Parity = SPACEPARITY;
\r
1502 dcb.StopBits = ONESTOPBIT;
\r
1505 // [HGM] args: these three cases taken out to stay in front-end
\r
1507 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
1508 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
1509 // while the curent board size determines the element. This system should be ported to XBoard.
\r
1510 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
1512 for (bs=0; bs<NUM_SIZES; bs++) {
\r
1513 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
1514 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
1515 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
1516 ad->argName, mfp->faceName, mfp->pointSize,
\r
1517 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
1518 mfp->bold ? "b" : "",
\r
1519 mfp->italic ? "i" : "",
\r
1520 mfp->underline ? "u" : "",
\r
1521 mfp->strikeout ? "s" : "",
\r
1522 (int)mfp->charset);
\r
1528 { // [HGM] copy the names from the internal WB variables to appData
\r
1531 for (cc = (ColorClass)0; cc < ColorNormal; cc++)
\r
1532 (&appData.soundShout)[cc] = textAttribs[cc].sound.name;
\r
1533 for (sc = (SoundClass)0; sc < NSoundClasses; sc++)
\r
1534 (&appData.soundMove)[sc] = sounds[sc].name;
\r
1538 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
1539 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
1540 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
1541 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
1542 (ta->effects & CFE_BOLD) ? "b" : "",
\r
1543 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
1544 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
1545 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
1546 (ta->effects) ? " " : "",
\r
1547 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
1551 SaveColor(FILE *f, ArgDescriptor *ad)
\r
1552 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
1553 COLORREF color = *(COLORREF *)colorVariable[(int)ad->argLoc];
\r
1554 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
1555 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
1559 SaveBoardSize(FILE *f, char *name, void *addr)
\r
1560 { // wrapper to shield back-end from BoardSize & sizeInfo
\r
1561 fprintf(f, "/%s=%s\n", name, sizeInfo[*(BoardSize *)addr].name);
\r
1565 ParseCommPortSettings(char *s)
\r
1566 { // wrapper to keep dcb from back-end
\r
1567 ParseCommSettings(s, &dcb);
\r
1572 { // wrapper to shield use of window handles from back-end (make addressible by number?)
\r
1573 GetActualPlacement(hwndMain, &wpMain);
\r
1574 GetActualPlacement(hwndConsole, &wpConsole);
\r
1575 GetActualPlacement(commentDialog, &wpComment);
\r
1576 GetActualPlacement(editTagsDialog, &wpTags);
\r
1577 GetActualPlacement(gameListDialog, &wpGameList);
\r
1578 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
1579 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
1580 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
1584 PrintCommPortSettings(FILE *f, char *name)
\r
1585 { // wrapper to shield back-end from DCB
\r
1586 PrintCommSettings(f, name, &dcb);
\r
1590 MySearchPath(char *installDir, char *name, char *fullname)
\r
1592 char *dummy, buf[MSG_SIZ], *p = name, *q;
\r
1593 if(name[0]== '%') {
\r
1594 fullname[0] = 0; // [HGM] first expand any environment variables in the given name
\r
1595 while(*p == '%' && (q = strchr(p+1, '%'))) { // [HGM] recognize %*% as environment variable
\r
1596 safeStrCpy(buf, p+1, sizeof(buf)/sizeof(buf[0]) );
\r
1597 *strchr(buf, '%') = 0;
\r
1598 strcat(fullname, getenv(buf));
\r
1599 p = q+1; while(*p == '\\') { strcat(fullname, "\\"); p++; }
\r
1601 strcat(fullname, p); // after environment variables (if any), take the remainder of the given name
\r
1602 if(appData.debugMode) fprintf(debugFP, "name = '%s', expanded name = '%s'\n", name, fullname);
\r
1603 return (int) strlen(fullname);
\r
1605 return (int) SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1609 MyGetFullPathName(char *name, char *fullname)
\r
1612 return (int) GetFullPathName(name, MSG_SIZ, fullname, &dummy);
\r
1617 { // [HGM] args: allows testing if main window is realized from back-end
\r
1618 return hwndMain != NULL;
\r
1622 PopUpStartupDialog()
\r
1626 LoadLanguageFile(appData.language);
\r
1627 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1628 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1629 FreeProcInstance(lpProc);
\r
1632 /*---------------------------------------------------------------------------*\
\r
1634 * GDI board drawing routines
\r
1636 \*---------------------------------------------------------------------------*/
\r
1638 /* [AS] Draw square using background texture */
\r
1639 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
1644 return; /* Should never happen! */
\r
1647 SetGraphicsMode( dst, GM_ADVANCED );
\r
1654 /* X reflection */
\r
1659 x.eDx = (FLOAT) dw + dx - 1;
\r
1662 SetWorldTransform( dst, &x );
\r
1665 /* Y reflection */
\r
1671 x.eDy = (FLOAT) dh + dy - 1;
\r
1673 SetWorldTransform( dst, &x );
\r
1681 x.eDx = (FLOAT) dx;
\r
1682 x.eDy = (FLOAT) dy;
\r
1685 SetWorldTransform( dst, &x );
\r
1689 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
1697 SetWorldTransform( dst, &x );
\r
1699 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
1702 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
1704 PM_WP = (int) WhitePawn,
\r
1705 PM_WN = (int) WhiteKnight,
\r
1706 PM_WB = (int) WhiteBishop,
\r
1707 PM_WR = (int) WhiteRook,
\r
1708 PM_WQ = (int) WhiteQueen,
\r
1709 PM_WF = (int) WhiteFerz,
\r
1710 PM_WW = (int) WhiteWazir,
\r
1711 PM_WE = (int) WhiteAlfil,
\r
1712 PM_WM = (int) WhiteMan,
\r
1713 PM_WO = (int) WhiteCannon,
\r
1714 PM_WU = (int) WhiteUnicorn,
\r
1715 PM_WH = (int) WhiteNightrider,
\r
1716 PM_WA = (int) WhiteAngel,
\r
1717 PM_WC = (int) WhiteMarshall,
\r
1718 PM_WAB = (int) WhiteCardinal,
\r
1719 PM_WD = (int) WhiteDragon,
\r
1720 PM_WL = (int) WhiteLance,
\r
1721 PM_WS = (int) WhiteCobra,
\r
1722 PM_WV = (int) WhiteFalcon,
\r
1723 PM_WSG = (int) WhiteSilver,
\r
1724 PM_WG = (int) WhiteGrasshopper,
\r
1725 PM_WK = (int) WhiteKing,
\r
1726 PM_BP = (int) BlackPawn,
\r
1727 PM_BN = (int) BlackKnight,
\r
1728 PM_BB = (int) BlackBishop,
\r
1729 PM_BR = (int) BlackRook,
\r
1730 PM_BQ = (int) BlackQueen,
\r
1731 PM_BF = (int) BlackFerz,
\r
1732 PM_BW = (int) BlackWazir,
\r
1733 PM_BE = (int) BlackAlfil,
\r
1734 PM_BM = (int) BlackMan,
\r
1735 PM_BO = (int) BlackCannon,
\r
1736 PM_BU = (int) BlackUnicorn,
\r
1737 PM_BH = (int) BlackNightrider,
\r
1738 PM_BA = (int) BlackAngel,
\r
1739 PM_BC = (int) BlackMarshall,
\r
1740 PM_BG = (int) BlackGrasshopper,
\r
1741 PM_BAB = (int) BlackCardinal,
\r
1742 PM_BD = (int) BlackDragon,
\r
1743 PM_BL = (int) BlackLance,
\r
1744 PM_BS = (int) BlackCobra,
\r
1745 PM_BV = (int) BlackFalcon,
\r
1746 PM_BSG = (int) BlackSilver,
\r
1747 PM_BK = (int) BlackKing
\r
1750 static HFONT hPieceFont = NULL;
\r
1751 static HBITMAP hPieceMask[(int) EmptySquare];
\r
1752 static HBITMAP hPieceFace[(int) EmptySquare];
\r
1753 static int fontBitmapSquareSize = 0;
\r
1754 static char pieceToFontChar[(int) EmptySquare] =
\r
1755 { 'p', 'n', 'b', 'r', 'q',
\r
1756 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
1757 'k', 'o', 'm', 'v', 't', 'w',
\r
1758 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
1761 extern BOOL SetCharTable( char *table, const char * map );
\r
1762 /* [HGM] moved to backend.c */
\r
1764 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
1767 BYTE r1 = GetRValue( color );
\r
1768 BYTE g1 = GetGValue( color );
\r
1769 BYTE b1 = GetBValue( color );
\r
1775 /* Create a uniform background first */
\r
1776 hbrush = CreateSolidBrush( color );
\r
1777 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
1778 FillRect( hdc, &rc, hbrush );
\r
1779 DeleteObject( hbrush );
\r
1782 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
1783 int steps = squareSize / 2;
\r
1786 for( i=0; i<steps; i++ ) {
\r
1787 BYTE r = r1 - (r1-r2) * i / steps;
\r
1788 BYTE g = g1 - (g1-g2) * i / steps;
\r
1789 BYTE b = b1 - (b1-b2) * i / steps;
\r
1791 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1792 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
1793 FillRect( hdc, &rc, hbrush );
\r
1794 DeleteObject(hbrush);
\r
1797 else if( mode == 2 ) {
\r
1798 /* Diagonal gradient, good more or less for every piece */
\r
1799 POINT triangle[3];
\r
1800 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
1801 HBRUSH hbrush_old;
\r
1802 int steps = squareSize;
\r
1805 triangle[0].x = squareSize - steps;
\r
1806 triangle[0].y = squareSize;
\r
1807 triangle[1].x = squareSize;
\r
1808 triangle[1].y = squareSize;
\r
1809 triangle[2].x = squareSize;
\r
1810 triangle[2].y = squareSize - steps;
\r
1812 for( i=0; i<steps; i++ ) {
\r
1813 BYTE r = r1 - (r1-r2) * i / steps;
\r
1814 BYTE g = g1 - (g1-g2) * i / steps;
\r
1815 BYTE b = b1 - (b1-b2) * i / steps;
\r
1817 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
1818 hbrush_old = SelectObject( hdc, hbrush );
\r
1819 Polygon( hdc, triangle, 3 );
\r
1820 SelectObject( hdc, hbrush_old );
\r
1821 DeleteObject(hbrush);
\r
1826 SelectObject( hdc, hpen );
\r
1831 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
1832 seems to work ok. The main problem here is to find the "inside" of a chess
\r
1833 piece: follow the steps as explained below.
\r
1835 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
1839 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
1845 int backColor = whitePieceColor;
\r
1846 int foreColor = blackPieceColor;
\r
1848 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
1849 backColor = appData.fontBackColorWhite;
\r
1850 foreColor = appData.fontForeColorWhite;
\r
1852 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
1853 backColor = appData.fontBackColorBlack;
\r
1854 foreColor = appData.fontForeColorBlack;
\r
1858 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1860 hbm_old = SelectObject( hdc, hbm );
\r
1864 rc.right = squareSize;
\r
1865 rc.bottom = squareSize;
\r
1867 /* Step 1: background is now black */
\r
1868 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
1870 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
1872 pt.x = (squareSize - sz.cx) / 2;
\r
1873 pt.y = (squareSize - sz.cy) / 2;
\r
1875 SetBkMode( hdc, TRANSPARENT );
\r
1876 SetTextColor( hdc, chroma );
\r
1877 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
1878 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1880 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
1881 /* Step 3: the area outside the piece is filled with white */
\r
1882 // FloodFill( hdc, 0, 0, chroma );
\r
1883 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
1884 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
1885 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
1886 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
1887 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
1889 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
1890 but if the start point is not inside the piece we're lost!
\r
1891 There should be a better way to do this... if we could create a region or path
\r
1892 from the fill operation we would be fine for example.
\r
1894 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
1895 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
1897 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
1898 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1899 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1901 SelectObject( dc2, bm2 );
\r
1902 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
1903 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1904 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1905 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1906 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
1909 DeleteObject( bm2 );
\r
1912 SetTextColor( hdc, 0 );
\r
1914 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
1915 draw the piece again in black for safety.
\r
1917 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1919 SelectObject( hdc, hbm_old );
\r
1921 if( hPieceMask[index] != NULL ) {
\r
1922 DeleteObject( hPieceMask[index] );
\r
1925 hPieceMask[index] = hbm;
\r
1928 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1930 SelectObject( hdc, hbm );
\r
1933 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
1934 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
1935 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
1937 SelectObject( dc1, hPieceMask[index] );
\r
1938 SelectObject( dc2, bm2 );
\r
1939 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
1940 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
1943 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
1944 the piece background and deletes (makes transparent) the rest.
\r
1945 Thanks to that mask, we are free to paint the background with the greates
\r
1946 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
1947 We use this, to make gradients and give the pieces a "roundish" look.
\r
1949 SetPieceBackground( hdc, backColor, 2 );
\r
1950 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
1954 DeleteObject( bm2 );
\r
1957 SetTextColor( hdc, foreColor );
\r
1958 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
1960 SelectObject( hdc, hbm_old );
\r
1962 if( hPieceFace[index] != NULL ) {
\r
1963 DeleteObject( hPieceFace[index] );
\r
1966 hPieceFace[index] = hbm;
\r
1969 static int TranslatePieceToFontPiece( int piece )
\r
1999 case BlackMarshall:
\r
2003 case BlackNightrider:
\r
2009 case BlackUnicorn:
\r
2013 case BlackGrasshopper:
\r
2025 case BlackCardinal:
\r
2032 case WhiteMarshall:
\r
2036 case WhiteNightrider:
\r
2042 case WhiteUnicorn:
\r
2046 case WhiteGrasshopper:
\r
2058 case WhiteCardinal:
\r
2067 void CreatePiecesFromFont()
\r
2070 HDC hdc_window = NULL;
\r
2076 if( fontBitmapSquareSize < 0 ) {
\r
2077 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2081 if( !appData.useFont || appData.renderPiecesWithFont == NULL ||
\r
2082 appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2083 fontBitmapSquareSize = -1;
\r
2087 if( fontBitmapSquareSize != squareSize ) {
\r
2088 hdc_window = GetDC( hwndMain );
\r
2089 hdc = CreateCompatibleDC( hdc_window );
\r
2091 if( hPieceFont != NULL ) {
\r
2092 DeleteObject( hPieceFont );
\r
2095 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2096 hPieceMask[i] = NULL;
\r
2097 hPieceFace[i] = NULL;
\r
2103 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2104 fontHeight = appData.fontPieceSize;
\r
2107 fontHeight = (fontHeight * squareSize) / 100;
\r
2109 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2111 lf.lfEscapement = 0;
\r
2112 lf.lfOrientation = 0;
\r
2113 lf.lfWeight = FW_NORMAL;
\r
2115 lf.lfUnderline = 0;
\r
2116 lf.lfStrikeOut = 0;
\r
2117 lf.lfCharSet = DEFAULT_CHARSET;
\r
2118 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2119 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2120 lf.lfQuality = PROOF_QUALITY;
\r
2121 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2122 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2123 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2125 hPieceFont = CreateFontIndirect( &lf );
\r
2127 if( hPieceFont == NULL ) {
\r
2128 fontBitmapSquareSize = -2;
\r
2131 /* Setup font-to-piece character table */
\r
2132 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2133 /* No (or wrong) global settings, try to detect the font */
\r
2134 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2136 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2138 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2139 /* DiagramTT* family */
\r
2140 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2142 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2143 /* Fairy symbols */
\r
2144 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2146 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2147 /* Good Companion (Some characters get warped as literal :-( */
\r
2148 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2149 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2150 SetCharTable(pieceToFontChar, s);
\r
2153 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2154 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2158 /* Create bitmaps */
\r
2159 hfont_old = SelectObject( hdc, hPieceFont );
\r
2160 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2161 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2162 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2164 SelectObject( hdc, hfont_old );
\r
2166 fontBitmapSquareSize = squareSize;
\r
2170 if( hdc != NULL ) {
\r
2174 if( hdc_window != NULL ) {
\r
2175 ReleaseDC( hwndMain, hdc_window );
\r
2180 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2182 char name[128], buf[MSG_SIZ];
\r
2184 snprintf(name, sizeof(name)/sizeof(name[0]), "%s%d%s", piece, squareSize, suffix);
\r
2185 if(appData.pieceDirectory[0]) {
\r
2187 snprintf(buf, MSG_SIZ, "%s\\%s.bmp", appData.pieceDirectory, name);
\r
2188 res = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
2189 if(res) return res;
\r
2191 if (gameInfo.event &&
\r
2192 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2193 strcmp(name, "k80s") == 0) {
\r
2194 safeStrCpy(name, "tim", sizeof(name)/sizeof(name[0]) );
\r
2196 return LoadBitmap(hinst, name);
\r
2200 /* Insert a color into the program's logical palette
\r
2201 structure. This code assumes the given color is
\r
2202 the result of the RGB or PALETTERGB macro, and it
\r
2203 knows how those macros work (which is documented).
\r
2206 InsertInPalette(COLORREF color)
\r
2208 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2210 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2211 DisplayFatalError(_("Too many colors"), 0, 1);
\r
2212 pLogPal->palNumEntries--;
\r
2216 pe->peFlags = (char) 0;
\r
2217 pe->peRed = (char) (0xFF & color);
\r
2218 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2219 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2225 InitDrawingColors()
\r
2228 if (pLogPal == NULL) {
\r
2229 /* Allocate enough memory for a logical palette with
\r
2230 * PALETTESIZE entries and set the size and version fields
\r
2231 * of the logical palette structure.
\r
2233 pLogPal = (NPLOGPALETTE)
\r
2234 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2235 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2236 pLogPal->palVersion = 0x300;
\r
2238 pLogPal->palNumEntries = 0;
\r
2240 InsertInPalette(lightSquareColor);
\r
2241 InsertInPalette(darkSquareColor);
\r
2242 InsertInPalette(whitePieceColor);
\r
2243 InsertInPalette(blackPieceColor);
\r
2244 InsertInPalette(highlightSquareColor);
\r
2245 InsertInPalette(premoveHighlightColor);
\r
2247 /* create a logical color palette according the information
\r
2248 * in the LOGPALETTE structure.
\r
2250 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2252 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2253 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2254 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2255 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2256 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2257 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2258 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2259 for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers
\r
2261 /* [AS] Force rendering of the font-based pieces */
\r
2262 if( fontBitmapSquareSize > 0 ) {
\r
2263 fontBitmapSquareSize = 0;
\r
2269 BoardWidth(int boardSize, int n)
\r
2270 { /* [HGM] argument n added to allow different width and height */
\r
2271 int lineGap = sizeInfo[boardSize].lineGap;
\r
2273 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2274 lineGap = appData.overrideLineGap;
\r
2277 return (n + 1) * lineGap +
\r
2278 n * sizeInfo[boardSize].squareSize;
\r
2281 /* Respond to board resize by dragging edge */
\r
2283 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2285 BoardSize newSize = NUM_SIZES - 1;
\r
2286 static int recurse = 0;
\r
2287 if (IsIconic(hwndMain)) return;
\r
2288 if (recurse > 0) return;
\r
2290 while (newSize > 0) {
\r
2291 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2292 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2293 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2296 boardSize = newSize;
\r
2297 InitDrawingSizes(boardSize, flags);
\r
2302 extern Boolean twoBoards, partnerUp; // [HGM] dual
\r
2305 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2307 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2308 ChessSquare piece;
\r
2309 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2311 SIZE clockSize, messageSize;
\r
2313 char buf[MSG_SIZ];
\r
2315 HMENU hmenu = GetMenu(hwndMain);
\r
2316 RECT crect, wrect, oldRect;
\r
2318 LOGBRUSH logbrush;
\r
2319 VariantClass v = gameInfo.variant;
\r
2321 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2322 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2324 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2325 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2326 if(boardSize == -1) return; // no size defined yet; abort (to allow early call of InitPosition)
\r
2327 oldBoardSize = boardSize;
\r
2329 if(boardSize != SizeMiddling && boardSize != SizePetite && boardSize != SizeBulky && !appData.useFont)
\r
2330 { // correct board size to one where built-in pieces exist
\r
2331 if((v == VariantCapablanca || v == VariantGothic || v == VariantGrand || v == VariantCapaRandom || v == VariantJanus || v == VariantSuper)
\r
2332 && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range
\r
2334 || (v == VariantShogi && boardSize != SizeModerate) // Japanese-style Shogi
\r
2335 || v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan
\r
2336 || v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {
\r
2337 if(boardSize < SizeMediocre) boardSize = SizePetite; else
\r
2338 if(boardSize > SizeModerate) boardSize = SizeBulky; else
\r
2339 boardSize = SizeMiddling;
\r
2342 if(!appData.useFont && boardSize == SizePetite && (v == VariantKnightmate)) boardSize = SizeMiddling; // no Unicorn in Petite
\r
2344 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2345 oldRect.top = wpMain.y;
\r
2346 oldRect.right = wpMain.x + wpMain.width;
\r
2347 oldRect.bottom = wpMain.y + wpMain.height;
\r
2349 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2350 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2351 squareSize = sizeInfo[boardSize].squareSize;
\r
2352 lineGap = sizeInfo[boardSize].lineGap;
\r
2353 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2354 border = appData.useBorder && appData.border[0] ? squareSize/2 : 0;
\r
2356 // [HGM] decide on tininess based on total board width rather than square size
\r
2357 tinyLayout = squareSize * (BOARD_WIDTH);
\r
2358 tinyLayout = tinyLayout < 35*8 ? 2 : tinyLayout < 43*8 ? 1 : 0;
\r
2360 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2361 lineGap = appData.overrideLineGap;
\r
2364 if (tinyLayout != oldTinyLayout) {
\r
2365 long style = GetWindowLongPtr(hwndMain, GWL_STYLE);
\r
2366 if (tinyLayout == 2) {
\r
2367 style &= ~WS_SYSMENU;
\r
2368 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2369 "&Minimize\tCtrl+F4");
\r
2371 style |= WS_SYSMENU;
\r
2372 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2374 SetWindowLongPtr(hwndMain, GWL_STYLE, style);
\r
2376 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2377 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2378 (UINT)GetSubMenu(hmenu, i), T_(menuBarText[tinyLayout][i]));
\r
2380 DrawMenuBar(hwndMain);
\r
2383 boardWidth = BoardWidth(boardSize, BOARD_WIDTH) + 2*border;
\r
2384 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT) + 2*border;
\r
2386 /* Get text area sizes */
\r
2387 hdc = GetDC(hwndMain);
\r
2388 if (appData.clockMode) {
\r
2389 snprintf(buf, MSG_SIZ, _("White: %s"), TimeString(23*60*60*1000L));
\r
2391 snprintf(buf, MSG_SIZ, _("White"));
\r
2393 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2394 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2395 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2396 str = _("We only care about the height here");
\r
2397 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2398 SelectObject(hdc, oldFont);
\r
2399 ReleaseDC(hwndMain, hdc);
\r
2401 /* Compute where everything goes */
\r
2402 if((first.programLogo || second.programLogo) && tinyLayout != 2) {
\r
2403 /* [HGM] logo: if either logo is on, reserve space for it */
\r
2404 logoHeight = 2*clockSize.cy;
\r
2405 leftLogoRect.left = OUTER_MARGIN;
\r
2406 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
2407 leftLogoRect.top = OUTER_MARGIN;
\r
2408 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2410 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
2411 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
2412 rightLogoRect.top = OUTER_MARGIN;
\r
2413 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
2416 whiteRect.left = leftLogoRect.right;
\r
2417 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
2418 whiteRect.top = OUTER_MARGIN;
\r
2419 whiteRect.bottom = whiteRect.top + logoHeight;
\r
2421 blackRect.right = rightLogoRect.left;
\r
2422 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2423 blackRect.top = whiteRect.top;
\r
2424 blackRect.bottom = whiteRect.bottom;
\r
2426 whiteRect.left = OUTER_MARGIN;
\r
2427 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2428 whiteRect.top = OUTER_MARGIN;
\r
2429 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2431 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2432 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2433 blackRect.top = whiteRect.top;
\r
2434 blackRect.bottom = whiteRect.bottom;
\r
2436 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
2439 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
2440 if (appData.showButtonBar) {
\r
2441 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
2442 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2444 messageRect.right = OUTER_MARGIN + boardWidth;
\r
2446 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2447 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2449 boardRect.left = OUTER_MARGIN;
\r
2450 boardRect.right = boardRect.left + boardWidth;
\r
2451 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2452 boardRect.bottom = boardRect.top + boardHeight;
\r
2454 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2455 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2456 oldTinyLayout = tinyLayout;
\r
2457 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2458 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2459 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2460 winW *= 1 + twoBoards;
\r
2461 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
2462 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
2463 wpMain.height = winH; // without disturbing window attachments
\r
2464 GetWindowRect(hwndMain, &wrect);
\r
2465 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2466 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2468 // [HGM] placement: let attached windows follow size change.
\r
2469 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
2470 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
2471 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
2472 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
2473 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
2475 /* compensate if menu bar wrapped */
\r
2476 GetClientRect(hwndMain, &crect);
\r
2477 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2478 wpMain.height += offby;
\r
2480 case WMSZ_TOPLEFT:
\r
2481 SetWindowPos(hwndMain, NULL,
\r
2482 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
2483 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2486 case WMSZ_TOPRIGHT:
\r
2488 SetWindowPos(hwndMain, NULL,
\r
2489 wrect.left, wrect.bottom - wpMain.height,
\r
2490 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2493 case WMSZ_BOTTOMLEFT:
\r
2495 SetWindowPos(hwndMain, NULL,
\r
2496 wrect.right - wpMain.width, wrect.top,
\r
2497 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2500 case WMSZ_BOTTOMRIGHT:
\r
2504 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
2505 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2510 for (i = 0; i < N_BUTTONS; i++) {
\r
2511 if (buttonDesc[i].hwnd != NULL) {
\r
2512 DestroyWindow(buttonDesc[i].hwnd);
\r
2513 buttonDesc[i].hwnd = NULL;
\r
2515 if (appData.showButtonBar) {
\r
2516 buttonDesc[i].hwnd =
\r
2517 CreateWindow("BUTTON", buttonDesc[i].label,
\r
2518 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
2519 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
2520 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
2521 (HMENU) buttonDesc[i].id,
\r
2522 (HINSTANCE) GetWindowLongPtr(hwndMain, GWLP_HINSTANCE), NULL);
\r
2523 if (tinyLayout == 2) {
\r
2524 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
2525 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
2526 MAKELPARAM(FALSE, 0));
\r
2528 if (buttonDesc[i].id == IDM_Pause)
\r
2529 hwndPause = buttonDesc[i].hwnd;
\r
2530 buttonDesc[i].wndproc = (WNDPROC)
\r
2531 SetWindowLongPtr(buttonDesc[i].hwnd, GWLP_WNDPROC, (LONG_PTR) ButtonProc);
\r
2534 if (gridPen != NULL) DeleteObject(gridPen);
\r
2535 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
2536 if (premovePen != NULL) DeleteObject(premovePen);
\r
2537 if (lineGap != 0) {
\r
2538 logbrush.lbStyle = BS_SOLID;
\r
2539 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
2541 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2542 lineGap, &logbrush, 0, NULL);
\r
2543 logbrush.lbColor = highlightSquareColor;
\r
2545 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2546 lineGap, &logbrush, 0, NULL);
\r
2548 logbrush.lbColor = premoveHighlightColor;
\r
2550 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
2551 lineGap, &logbrush, 0, NULL);
\r
2553 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
2554 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
2555 gridEndpoints[i*2].x = boardRect.left + lineGap / 2 + border;
\r
2556 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
2557 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2558 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
2559 BOARD_WIDTH * (squareSize + lineGap) + border;
\r
2560 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2562 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
2563 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2 + border;
\r
2564 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
2565 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
2566 lineGap / 2 + (i * (squareSize + lineGap)) + border;
\r
2567 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
2568 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap) + border;
\r
2569 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
2573 /* [HGM] Licensing requirement */
\r
2575 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
2578 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
2580 GothicPopUp( "", VariantNormal);
\r
2583 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
2585 /* Load piece bitmaps for this board size */
\r
2586 for (i=0; i<=2; i++) {
\r
2587 for (piece = WhitePawn;
\r
2588 (int) piece < (int) BlackPawn;
\r
2589 piece = (ChessSquare) ((int) piece + 1)) {
\r
2590 if (pieceBitmap[i][piece] != NULL)
\r
2591 DeleteObject(pieceBitmap[i][piece]);
\r
2595 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2596 // Orthodox Chess pieces
\r
2597 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2598 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2599 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2600 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2601 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2602 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2603 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2604 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2605 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2606 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2607 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2608 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2609 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2610 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2611 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2612 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2613 // in Shogi, Hijack the unused Queen for Lance
\r
2614 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2615 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2616 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2618 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2619 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2620 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2623 if(squareSize <= 72 && squareSize >= 33) {
\r
2624 /* A & C are available in most sizes now */
\r
2625 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2626 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2627 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2628 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2629 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2630 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2631 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2632 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2633 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2634 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2635 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2636 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2637 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2638 } else { // Smirf-like
\r
2639 if(gameInfo.variant == VariantSChess) {
\r
2640 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2641 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2642 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2644 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2645 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2646 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2649 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2650 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2651 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2652 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2653 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2654 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2655 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2656 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2657 } else { // WinBoard standard
\r
2658 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2659 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2660 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2665 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2666 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2667 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2668 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2669 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2670 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2671 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2672 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2673 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2674 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2675 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2676 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2677 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2678 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2679 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2680 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2681 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2682 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2683 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2684 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2685 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2686 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2687 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2688 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2689 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2690 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2691 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2692 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2693 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2694 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2695 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2696 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2697 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2698 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2700 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2701 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2702 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2703 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2704 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2705 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2706 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2707 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2708 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2709 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2710 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2711 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2712 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2714 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2715 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2716 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2717 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2718 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2719 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2720 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2721 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2722 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2723 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2724 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2725 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2728 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2729 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2730 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2731 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2732 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2733 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2734 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2735 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2736 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2737 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2738 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2739 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2740 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2741 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2742 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2746 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2747 /* special Shogi support in this size */
\r
2748 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2749 for (piece = WhitePawn;
\r
2750 (int) piece < (int) BlackPawn;
\r
2751 piece = (ChessSquare) ((int) piece + 1)) {
\r
2752 if (pieceBitmap[i][piece] != NULL)
\r
2753 DeleteObject(pieceBitmap[i][piece]);
\r
2756 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2757 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2758 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2764 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2765 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2766 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2767 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2768 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2769 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2770 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2771 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2772 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2778 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2779 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2780 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2781 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2782 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2783 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2784 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2785 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2786 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2792 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2793 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2794 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2795 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2796 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2797 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2803 PieceBitmap(ChessSquare p, int kind)
\r
2805 if ((int) p >= (int) BlackPawn)
\r
2806 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2808 return pieceBitmap[kind][(int) p];
\r
2811 /***************************************************************/
\r
2813 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2814 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2816 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2817 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2821 SquareToPos(int row, int column, int * x, int * y)
\r
2824 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2825 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2827 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2828 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2833 DrawCoordsOnDC(HDC hdc)
\r
2835 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2836 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2837 char str[2] = { NULLCHAR, NULLCHAR };
\r
2838 int oldMode, oldAlign, x, y, start, i;
\r
2842 if (!appData.showCoords)
\r
2845 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2847 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2848 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2849 oldAlign = GetTextAlign(hdc);
\r
2850 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2852 y = boardRect.top + lineGap;
\r
2853 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2856 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2857 x += border - lineGap - 4; y += squareSize - 6;
\r
2859 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2860 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2861 str[0] = files[start + i];
\r
2862 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2863 y += squareSize + lineGap;
\r
2866 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2869 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2870 x += -border + 4; y += border - squareSize + 6;
\r
2872 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2873 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2874 str[0] = ranks[start + i];
\r
2875 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2876 x += squareSize + lineGap;
\r
2879 SelectObject(hdc, oldBrush);
\r
2880 SetBkMode(hdc, oldMode);
\r
2881 SetTextAlign(hdc, oldAlign);
\r
2882 SelectObject(hdc, oldFont);
\r
2886 DrawGridOnDC(HDC hdc)
\r
2890 if (lineGap != 0) {
\r
2891 oldPen = SelectObject(hdc, gridPen);
\r
2892 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2893 SelectObject(hdc, oldPen);
\r
2897 #define HIGHLIGHT_PEN 0
\r
2898 #define PREMOVE_PEN 1
\r
2901 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2904 HPEN oldPen, hPen;
\r
2905 if (lineGap == 0) return;
\r
2907 x1 = boardRect.left +
\r
2908 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2909 y1 = boardRect.top +
\r
2910 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2912 x1 = boardRect.left +
\r
2913 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2914 y1 = boardRect.top +
\r
2915 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2917 hPen = pen ? premovePen : highlightPen;
\r
2918 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2919 MoveToEx(hdc, x1, y1, NULL);
\r
2920 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2921 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2922 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2923 LineTo(hdc, x1, y1);
\r
2924 SelectObject(hdc, oldPen);
\r
2928 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2931 for (i=0; i<2; i++) {
\r
2932 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2933 DrawHighlightOnDC(hdc, TRUE,
\r
2934 h->sq[i].x, h->sq[i].y,
\r
2939 /* Note: sqcolor is used only in monoMode */
\r
2940 /* Note that this code is largely duplicated in woptions.c,
\r
2941 function DrawSampleSquare, so that needs to be updated too */
\r
2943 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2945 HBITMAP oldBitmap;
\r
2949 if (appData.blindfold) return;
\r
2951 /* [AS] Use font-based pieces if needed */
\r
2952 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2953 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2954 CreatePiecesFromFont();
\r
2956 if( fontBitmapSquareSize == squareSize ) {
\r
2957 int index = TranslatePieceToFontPiece(piece);
\r
2959 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2961 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2962 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2966 squareSize, squareSize,
\r
2971 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2973 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2974 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2978 squareSize, squareSize,
\r
2987 if (appData.monoMode) {
\r
2988 SelectObject(tmphdc, PieceBitmap(piece,
\r
2989 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
2990 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
2991 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
2993 HBRUSH xBrush = whitePieceBrush;
\r
2994 tmpSize = squareSize;
\r
2995 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
2997 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
2998 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
2999 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3000 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3001 x += (squareSize - minorSize)>>1;
\r
3002 y += squareSize - minorSize - 2;
\r
3003 tmpSize = minorSize;
\r
3005 if (color || appData.allWhite ) {
\r
3006 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3008 oldBrush = SelectObject(hdc, xBrush);
\r
3009 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3010 if(appData.upsideDown && color==flipView)
\r
3011 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3013 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3014 /* Use black for outline of white pieces */
\r
3015 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3016 if(appData.upsideDown && color==flipView)
\r
3017 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3019 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3020 } else if(appData.pieceDirectory[0]) {
\r
3021 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3022 oldBrush = SelectObject(hdc, xBrush);
\r
3023 if(appData.upsideDown && color==flipView)
\r
3024 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3026 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3027 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3028 if(appData.upsideDown && color==flipView)
\r
3029 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3031 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3033 /* Use square color for details of black pieces */
\r
3034 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3035 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3036 if(appData.upsideDown && !flipView)
\r
3037 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3039 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3041 SelectObject(hdc, oldBrush);
\r
3042 SelectObject(tmphdc, oldBitmap);
\r
3046 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3047 int GetBackTextureMode( int algo )
\r
3049 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3053 case BACK_TEXTURE_MODE_PLAIN:
\r
3054 result = 1; /* Always use identity map */
\r
3056 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3057 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3065 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3066 to handle redraws cleanly (as random numbers would always be different).
\r
3068 VOID RebuildTextureSquareInfo()
\r
3078 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3080 if( liteBackTexture != NULL ) {
\r
3081 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3082 lite_w = bi.bmWidth;
\r
3083 lite_h = bi.bmHeight;
\r
3087 if( darkBackTexture != NULL ) {
\r
3088 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3089 dark_w = bi.bmWidth;
\r
3090 dark_h = bi.bmHeight;
\r
3094 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3095 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3096 if( (col + row) & 1 ) {
\r
3098 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3099 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3100 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3102 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3103 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3104 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3106 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3107 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3112 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3113 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3114 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3116 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3117 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3118 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3120 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3121 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3128 /* [AS] Arrow highlighting support */
\r
3130 static double A_WIDTH = 5; /* Width of arrow body */
\r
3132 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3133 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3135 static double Sqr( double x )
\r
3140 static int Round( double x )
\r
3142 return (int) (x + 0.5);
\r
3145 /* Draw an arrow between two points using current settings */
\r
3146 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3149 double dx, dy, j, k, x, y;
\r
3151 if( d_x == s_x ) {
\r
3152 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3154 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3157 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3158 arrow[1].y = d_y - h;
\r
3160 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3161 arrow[2].y = d_y - h;
\r
3166 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3167 arrow[5].y = d_y - h;
\r
3169 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3170 arrow[4].y = d_y - h;
\r
3172 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3175 else if( d_y == s_y ) {
\r
3176 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3179 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3181 arrow[1].x = d_x - w;
\r
3182 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3184 arrow[2].x = d_x - w;
\r
3185 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3190 arrow[5].x = d_x - w;
\r
3191 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3193 arrow[4].x = d_x - w;
\r
3194 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3197 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3200 /* [AS] Needed a lot of paper for this! :-) */
\r
3201 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3202 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3204 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3206 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3211 arrow[0].x = Round(x - j);
\r
3212 arrow[0].y = Round(y + j*dx);
\r
3214 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3215 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3218 x = (double) d_x - k;
\r
3219 y = (double) d_y - k*dy;
\r
3222 x = (double) d_x + k;
\r
3223 y = (double) d_y + k*dy;
\r
3226 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3228 arrow[6].x = Round(x - j);
\r
3229 arrow[6].y = Round(y + j*dx);
\r
3231 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3232 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3234 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3235 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3240 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3241 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3244 Polygon( hdc, arrow, 7 );
\r
3247 /* [AS] Draw an arrow between two squares */
\r
3248 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3250 int s_x, s_y, d_x, d_y;
\r
3257 if( s_col == d_col && s_row == d_row ) {
\r
3261 /* Get source and destination points */
\r
3262 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3263 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3266 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3268 else if( d_y < s_y ) {
\r
3269 d_y += squareSize / 2 + squareSize / 4;
\r
3272 d_y += squareSize / 2;
\r
3276 d_x += squareSize / 2 - squareSize / 4;
\r
3278 else if( d_x < s_x ) {
\r
3279 d_x += squareSize / 2 + squareSize / 4;
\r
3282 d_x += squareSize / 2;
\r
3285 s_x += squareSize / 2;
\r
3286 s_y += squareSize / 2;
\r
3288 /* Adjust width */
\r
3289 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3292 stLB.lbStyle = BS_SOLID;
\r
3293 stLB.lbColor = appData.highlightArrowColor;
\r
3296 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3297 holdpen = SelectObject( hdc, hpen );
\r
3298 hbrush = CreateBrushIndirect( &stLB );
\r
3299 holdbrush = SelectObject( hdc, hbrush );
\r
3301 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3303 SelectObject( hdc, holdpen );
\r
3304 SelectObject( hdc, holdbrush );
\r
3305 DeleteObject( hpen );
\r
3306 DeleteObject( hbrush );
\r
3309 BOOL HasHighlightInfo()
\r
3311 BOOL result = FALSE;
\r
3313 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3314 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3325 BOOL IsDrawArrowEnabled()
\r
3327 BOOL result = FALSE;
\r
3329 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3336 VOID DrawArrowHighlight( HDC hdc )
\r
3338 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3339 DrawArrowBetweenSquares( hdc,
\r
3340 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3341 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3345 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3347 HRGN result = NULL;
\r
3349 if( HasHighlightInfo() ) {
\r
3350 int x1, y1, x2, y2;
\r
3351 int sx, sy, dx, dy;
\r
3353 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3354 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3356 sx = MIN( x1, x2 );
\r
3357 sy = MIN( y1, y2 );
\r
3358 dx = MAX( x1, x2 ) + squareSize;
\r
3359 dy = MAX( y1, y2 ) + squareSize;
\r
3361 result = CreateRectRgn( sx, sy, dx, dy );
\r
3368 Warning: this function modifies the behavior of several other functions.
\r
3370 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3371 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3372 repaint is scattered all over the place, which is not good for features such as
\r
3373 "arrow highlighting" that require a full repaint of the board.
\r
3375 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3376 user interaction, when speed is not so important) but especially to avoid errors
\r
3377 in the displayed graphics.
\r
3379 In such patched places, I always try refer to this function so there is a single
\r
3380 place to maintain knowledge.
\r
3382 To restore the original behavior, just return FALSE unconditionally.
\r
3384 BOOL IsFullRepaintPreferrable()
\r
3386 BOOL result = FALSE;
\r
3388 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3389 /* Arrow may appear on the board */
\r
3397 This function is called by DrawPosition to know whether a full repaint must
\r
3400 Only DrawPosition may directly call this function, which makes use of
\r
3401 some state information. Other function should call DrawPosition specifying
\r
3402 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3404 BOOL DrawPositionNeedsFullRepaint()
\r
3406 BOOL result = FALSE;
\r
3409 Probably a slightly better policy would be to trigger a full repaint
\r
3410 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3411 but animation is fast enough that it's difficult to notice.
\r
3413 if( animInfo.piece == EmptySquare ) {
\r
3414 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3422 static HBITMAP borderBitmap;
\r
3425 DrawBackgroundOnDC(HDC hdc)
\r
3431 static char oldBorder[MSG_SIZ];
\r
3432 int w = 600, h = 600, mode;
\r
3434 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3435 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3436 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3438 if(borderBitmap == NULL) { // loading failed, use white
\r
3439 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3442 tmphdc = CreateCompatibleDC(hdc);
\r
3443 hbm = SelectObject(tmphdc, borderBitmap);
\r
3444 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3448 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3449 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3450 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3451 SetStretchBltMode(hdc, mode);
\r
3452 SelectObject(tmphdc, hbm);
\r
3457 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3459 int row, column, x, y, square_color, piece_color;
\r
3460 ChessSquare piece;
\r
3462 HDC texture_hdc = NULL;
\r
3464 /* [AS] Initialize background textures if needed */
\r
3465 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3466 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3467 if( backTextureSquareSize != squareSize
\r
3468 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3469 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3470 backTextureSquareSize = squareSize;
\r
3471 RebuildTextureSquareInfo();
\r
3474 texture_hdc = CreateCompatibleDC( hdc );
\r
3477 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3478 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3480 SquareToPos(row, column, &x, &y);
\r
3482 piece = board[row][column];
\r
3484 square_color = ((column + row) % 2) == 1;
\r
3485 if( gameInfo.variant == VariantXiangqi ) {
\r
3486 square_color = !InPalace(row, column);
\r
3487 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3488 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3490 piece_color = (int) piece < (int) BlackPawn;
\r
3493 /* [HGM] holdings file: light square or black */
\r
3494 if(column == BOARD_LEFT-2) {
\r
3495 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3498 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3502 if(column == BOARD_RGHT + 1 ) {
\r
3503 if( row < gameInfo.holdingsSize )
\r
3506 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3510 if(column == BOARD_LEFT-1 ) /* left align */
\r
3511 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3512 else if( column == BOARD_RGHT) /* right align */
\r
3513 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3514 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3516 if (appData.monoMode) {
\r
3517 if (piece == EmptySquare) {
\r
3518 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3519 square_color ? WHITENESS : BLACKNESS);
\r
3521 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3524 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3525 /* [AS] Draw the square using a texture bitmap */
\r
3526 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3527 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3528 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3531 squareSize, squareSize,
\r
3534 backTextureSquareInfo[r][c].mode,
\r
3535 backTextureSquareInfo[r][c].x,
\r
3536 backTextureSquareInfo[r][c].y );
\r
3538 SelectObject( texture_hdc, hbm );
\r
3540 if (piece != EmptySquare) {
\r
3541 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3545 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3547 oldBrush = SelectObject(hdc, brush );
\r
3548 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3549 SelectObject(hdc, oldBrush);
\r
3550 if (piece != EmptySquare)
\r
3551 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3556 if( texture_hdc != NULL ) {
\r
3557 DeleteDC( texture_hdc );
\r
3561 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3562 void fputDW(FILE *f, int x)
\r
3564 fputc(x & 255, f);
\r
3565 fputc(x>>8 & 255, f);
\r
3566 fputc(x>>16 & 255, f);
\r
3567 fputc(x>>24 & 255, f);
\r
3570 #define MAX_CLIPS 200 /* more than enough */
\r
3573 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3575 // HBITMAP bufferBitmap;
\r
3580 int w = 100, h = 50;
\r
3582 if(logo == NULL) {
\r
3583 if(!logoHeight) return;
\r
3584 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3586 // GetClientRect(hwndMain, &Rect);
\r
3587 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3588 // Rect.bottom-Rect.top+1);
\r
3589 tmphdc = CreateCompatibleDC(hdc);
\r
3590 hbm = SelectObject(tmphdc, logo);
\r
3591 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3595 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3596 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3597 SelectObject(tmphdc, hbm);
\r
3605 HDC hdc = GetDC(hwndMain);
\r
3606 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3607 if(appData.autoLogo) {
\r
3609 switch(gameMode) { // pick logos based on game mode
\r
3610 case IcsObserving:
\r
3611 whiteLogo = second.programLogo; // ICS logo
\r
3612 blackLogo = second.programLogo;
\r
3615 case IcsPlayingWhite:
\r
3616 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3617 blackLogo = second.programLogo; // ICS logo
\r
3619 case IcsPlayingBlack:
\r
3620 whiteLogo = second.programLogo; // ICS logo
\r
3621 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3623 case TwoMachinesPlay:
\r
3624 if(first.twoMachinesColor[0] == 'b') {
\r
3625 whiteLogo = second.programLogo;
\r
3626 blackLogo = first.programLogo;
\r
3629 case MachinePlaysWhite:
\r
3630 blackLogo = userLogo;
\r
3632 case MachinePlaysBlack:
\r
3633 whiteLogo = userLogo;
\r
3634 blackLogo = first.programLogo;
\r
3637 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3638 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3639 ReleaseDC(hwndMain, hdc);
\r
3644 UpdateLogos(int display)
\r
3645 { // called after loading new engine(s), in tourney or from menu
\r
3646 LoadLogo(&first, 0, FALSE);
\r
3647 LoadLogo(&second, 1, appData.icsActive);
\r
3648 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3649 if(display) DisplayLogos();
\r
3652 static HDC hdcSeek;
\r
3654 // [HGM] seekgraph
\r
3655 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3658 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3659 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3660 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3661 SelectObject( hdcSeek, hp );
\r
3664 // front-end wrapper for drawing functions to do rectangles
\r
3665 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3670 if (hdcSeek == NULL) {
\r
3671 hdcSeek = GetDC(hwndMain);
\r
3672 if (!appData.monoMode) {
\r
3673 SelectPalette(hdcSeek, hPal, FALSE);
\r
3674 RealizePalette(hdcSeek);
\r
3677 hp = SelectObject( hdcSeek, gridPen );
\r
3678 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3679 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3680 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3681 SelectObject( hdcSeek, hp );
\r
3684 // front-end wrapper for putting text in graph
\r
3685 void DrawSeekText(char *buf, int x, int y)
\r
3688 SetBkMode( hdcSeek, TRANSPARENT );
\r
3689 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3690 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3693 void DrawSeekDot(int x, int y, int color)
\r
3695 int square = color & 0x80;
\r
3696 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3697 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3700 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3701 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3703 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3704 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3705 SelectObject(hdcSeek, oldBrush);
\r
3708 void DrawSeekOpen()
\r
3712 void DrawSeekClose()
\r
3717 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3719 static Board lastReq[2], lastDrawn[2];
\r
3720 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3721 static int lastDrawnFlipView = 0;
\r
3722 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3723 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3726 HBITMAP bufferBitmap;
\r
3727 HBITMAP oldBitmap;
\r
3729 HRGN clips[MAX_CLIPS];
\r
3730 ChessSquare dragged_piece = EmptySquare;
\r
3731 int nr = twoBoards*partnerUp;
\r
3733 /* I'm undecided on this - this function figures out whether a full
\r
3734 * repaint is necessary on its own, so there's no real reason to have the
\r
3735 * caller tell it that. I think this can safely be set to FALSE - but
\r
3736 * if we trust the callers not to request full repaints unnessesarily, then
\r
3737 * we could skip some clipping work. In other words, only request a full
\r
3738 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3739 * gamestart and similar) --Hawk
\r
3741 Boolean fullrepaint = repaint;
\r
3743 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3745 if( DrawPositionNeedsFullRepaint() ) {
\r
3746 fullrepaint = TRUE;
\r
3749 if (board == NULL) {
\r
3750 if (!lastReqValid[nr]) {
\r
3753 board = lastReq[nr];
\r
3755 CopyBoard(lastReq[nr], board);
\r
3756 lastReqValid[nr] = 1;
\r
3759 if (doingSizing) {
\r
3763 if (IsIconic(hwndMain)) {
\r
3767 if (hdc == NULL) {
\r
3768 hdc = GetDC(hwndMain);
\r
3769 if (!appData.monoMode) {
\r
3770 SelectPalette(hdc, hPal, FALSE);
\r
3771 RealizePalette(hdc);
\r
3775 releaseDC = FALSE;
\r
3778 /* Create some work-DCs */
\r
3779 hdcmem = CreateCompatibleDC(hdc);
\r
3780 tmphdc = CreateCompatibleDC(hdc);
\r
3782 /* If dragging is in progress, we temporarely remove the piece */
\r
3783 /* [HGM] or temporarily decrease count if stacked */
\r
3784 /* !! Moved to before board compare !! */
\r
3785 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3786 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3787 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3788 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3789 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3791 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3792 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3793 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3795 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3798 /* Figure out which squares need updating by comparing the
\r
3799 * newest board with the last drawn board and checking if
\r
3800 * flipping has changed.
\r
3802 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3803 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3804 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3805 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3806 SquareToPos(row, column, &x, &y);
\r
3807 clips[num_clips++] =
\r
3808 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3812 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3813 for (i=0; i<2; i++) {
\r
3814 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3815 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3816 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3817 lastDrawnHighlight.sq[i].y >= 0) {
\r
3818 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3819 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3820 clips[num_clips++] =
\r
3821 CreateRectRgn(x - lineGap, y - lineGap,
\r
3822 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3824 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3825 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3826 clips[num_clips++] =
\r
3827 CreateRectRgn(x - lineGap, y - lineGap,
\r
3828 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3832 for (i=0; i<2; i++) {
\r
3833 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3834 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3835 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3836 lastDrawnPremove.sq[i].y >= 0) {
\r
3837 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3838 lastDrawnPremove.sq[i].x, &x, &y);
\r
3839 clips[num_clips++] =
\r
3840 CreateRectRgn(x - lineGap, y - lineGap,
\r
3841 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3843 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3844 premoveHighlightInfo.sq[i].y >= 0) {
\r
3845 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3846 premoveHighlightInfo.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
3853 } else { // nr == 1
\r
3854 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3855 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3856 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3857 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3858 for (i=0; i<2; i++) {
\r
3859 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3860 partnerHighlightInfo.sq[i].y >= 0) {
\r
3861 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3862 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3863 clips[num_clips++] =
\r
3864 CreateRectRgn(x - lineGap, y - lineGap,
\r
3865 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3867 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3868 oldPartnerHighlight.sq[i].y >= 0) {
\r
3869 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3870 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3871 clips[num_clips++] =
\r
3872 CreateRectRgn(x - lineGap, y - lineGap,
\r
3873 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3878 fullrepaint = TRUE;
\r
3881 /* Create a buffer bitmap - this is the actual bitmap
\r
3882 * being written to. When all the work is done, we can
\r
3883 * copy it to the real DC (the screen). This avoids
\r
3884 * the problems with flickering.
\r
3886 GetClientRect(hwndMain, &Rect);
\r
3887 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3888 Rect.bottom-Rect.top+1);
\r
3889 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3890 if (!appData.monoMode) {
\r
3891 SelectPalette(hdcmem, hPal, FALSE);
\r
3894 /* Create clips for dragging */
\r
3895 if (!fullrepaint) {
\r
3896 if (dragInfo.from.x >= 0) {
\r
3897 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3898 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3900 if (dragInfo.start.x >= 0) {
\r
3901 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3902 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3904 if (dragInfo.pos.x >= 0) {
\r
3905 x = dragInfo.pos.x - squareSize / 2;
\r
3906 y = dragInfo.pos.y - squareSize / 2;
\r
3907 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3909 if (dragInfo.lastpos.x >= 0) {
\r
3910 x = dragInfo.lastpos.x - squareSize / 2;
\r
3911 y = dragInfo.lastpos.y - squareSize / 2;
\r
3912 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3916 /* Are we animating a move?
\r
3918 * - remove the piece from the board (temporarely)
\r
3919 * - calculate the clipping region
\r
3921 if (!fullrepaint) {
\r
3922 if (animInfo.piece != EmptySquare) {
\r
3923 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3924 x = boardRect.left + animInfo.lastpos.x;
\r
3925 y = boardRect.top + animInfo.lastpos.y;
\r
3926 x2 = boardRect.left + animInfo.pos.x;
\r
3927 y2 = boardRect.top + animInfo.pos.y;
\r
3928 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3929 /* Slight kludge. The real problem is that after AnimateMove is
\r
3930 done, the position on the screen does not match lastDrawn.
\r
3931 This currently causes trouble only on e.p. captures in
\r
3932 atomic, where the piece moves to an empty square and then
\r
3933 explodes. The old and new positions both had an empty square
\r
3934 at the destination, but animation has drawn a piece there and
\r
3935 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3936 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3940 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3941 if (num_clips == 0)
\r
3942 fullrepaint = TRUE;
\r
3944 /* Set clipping on the memory DC */
\r
3945 if (!fullrepaint) {
\r
3946 SelectClipRgn(hdcmem, clips[0]);
\r
3947 for (x = 1; x < num_clips; x++) {
\r
3948 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3949 abort(); // this should never ever happen!
\r
3953 /* Do all the drawing to the memory DC */
\r
3954 if(explodeInfo.radius) { // [HGM] atomic
\r
3956 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3957 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3958 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3959 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3960 x += squareSize/2;
\r
3961 y += squareSize/2;
\r
3962 if(!fullrepaint) {
\r
3963 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3964 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3966 DrawGridOnDC(hdcmem);
\r
3967 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3968 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3969 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3970 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3971 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3972 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3973 SelectObject(hdcmem, oldBrush);
\r
3975 if(border) DrawBackgroundOnDC(hdcmem);
\r
3976 DrawGridOnDC(hdcmem);
\r
3977 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3978 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3979 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3981 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3982 oldPartnerHighlight = partnerHighlightInfo;
\r
3984 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3986 if(nr == 0) // [HGM] dual: markers only on left board
\r
3987 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3988 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3989 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
3990 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
3991 SquareToPos(row, column, &x, &y);
\r
3992 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
3993 x + 3*squareSize/4, y + 3*squareSize/4);
\r
3994 SelectObject(hdcmem, oldBrush);
\r
3999 if( appData.highlightMoveWithArrow ) {
\r
4001 DrawArrowHighlight(hdcmem);
\r
4004 DrawCoordsOnDC(hdcmem);
\r
4006 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4007 /* to make sure lastDrawn contains what is actually drawn */
\r
4009 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4010 if (dragged_piece != EmptySquare) {
\r
4011 /* [HGM] or restack */
\r
4012 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4013 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4015 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4016 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4018 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4019 x = dragInfo.pos.x - squareSize / 2;
\r
4020 y = dragInfo.pos.y - squareSize / 2;
\r
4021 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4022 ((int) dragInfo.piece < (int) BlackPawn),
\r
4023 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4026 /* Put the animated piece back into place and draw it */
\r
4027 if (animInfo.piece != EmptySquare) {
\r
4028 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4029 x = boardRect.left + animInfo.pos.x;
\r
4030 y = boardRect.top + animInfo.pos.y;
\r
4031 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4032 ((int) animInfo.piece < (int) BlackPawn),
\r
4033 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4036 /* Release the bufferBitmap by selecting in the old bitmap
\r
4037 * and delete the memory DC
\r
4039 SelectObject(hdcmem, oldBitmap);
\r
4042 /* Set clipping on the target DC */
\r
4043 if (!fullrepaint) {
\r
4044 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4046 GetRgnBox(clips[x], &rect);
\r
4047 DeleteObject(clips[x]);
\r
4048 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4049 rect.right + wpMain.width/2, rect.bottom);
\r
4051 SelectClipRgn(hdc, clips[0]);
\r
4052 for (x = 1; x < num_clips; x++) {
\r
4053 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4054 abort(); // this should never ever happen!
\r
4058 /* Copy the new bitmap onto the screen in one go.
\r
4059 * This way we avoid any flickering
\r
4061 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4062 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4063 boardRect.right - boardRect.left,
\r
4064 boardRect.bottom - boardRect.top,
\r
4065 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4066 if(saveDiagFlag) {
\r
4067 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4068 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4070 GetObject(bufferBitmap, sizeof(b), &b);
\r
4071 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4072 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4073 bih.biWidth = b.bmWidth;
\r
4074 bih.biHeight = b.bmHeight;
\r
4076 bih.biBitCount = b.bmBitsPixel;
\r
4077 bih.biCompression = 0;
\r
4078 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4079 bih.biXPelsPerMeter = 0;
\r
4080 bih.biYPelsPerMeter = 0;
\r
4081 bih.biClrUsed = 0;
\r
4082 bih.biClrImportant = 0;
\r
4083 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4084 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4085 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4086 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4088 wb = b.bmWidthBytes;
\r
4090 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4091 int k = ((int*) pData)[i];
\r
4092 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4093 if(j >= 16) break;
\r
4095 if(j >= nrColors) nrColors = j+1;
\r
4097 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4099 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4100 for(w=0; w<(wb>>2); w+=2) {
\r
4101 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4102 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4103 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4104 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4105 pData[p++] = m | j<<4;
\r
4107 while(p&3) pData[p++] = 0;
\r
4110 wb = ((wb+31)>>5)<<2;
\r
4112 // write BITMAPFILEHEADER
\r
4113 fprintf(diagFile, "BM");
\r
4114 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4115 fputDW(diagFile, 0);
\r
4116 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4117 // write BITMAPINFOHEADER
\r
4118 fputDW(diagFile, 40);
\r
4119 fputDW(diagFile, b.bmWidth);
\r
4120 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4121 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4122 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4123 fputDW(diagFile, 0);
\r
4124 fputDW(diagFile, 0);
\r
4125 fputDW(diagFile, 0);
\r
4126 fputDW(diagFile, 0);
\r
4127 fputDW(diagFile, 0);
\r
4128 fputDW(diagFile, 0);
\r
4129 // write color table
\r
4131 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4132 // write bitmap data
\r
4133 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4134 fputc(pData[i], diagFile);
\r
4139 SelectObject(tmphdc, oldBitmap);
\r
4141 /* Massive cleanup */
\r
4142 for (x = 0; x < num_clips; x++)
\r
4143 DeleteObject(clips[x]);
\r
4146 DeleteObject(bufferBitmap);
\r
4149 ReleaseDC(hwndMain, hdc);
\r
4151 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4153 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4155 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4158 /* CopyBoard(lastDrawn, board);*/
\r
4159 lastDrawnHighlight = highlightInfo;
\r
4160 lastDrawnPremove = premoveHighlightInfo;
\r
4161 lastDrawnFlipView = flipView;
\r
4162 lastDrawnValid[nr] = 1;
\r
4165 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4170 saveDiagFlag = 1; diagFile = f;
\r
4171 HDCDrawPosition(NULL, TRUE, NULL);
\r
4179 /*---------------------------------------------------------------------------*\
\r
4180 | CLIENT PAINT PROCEDURE
\r
4181 | This is the main event-handler for the WM_PAINT message.
\r
4183 \*---------------------------------------------------------------------------*/
\r
4185 PaintProc(HWND hwnd)
\r
4191 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4192 if (IsIconic(hwnd)) {
\r
4193 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4195 if (!appData.monoMode) {
\r
4196 SelectPalette(hdc, hPal, FALSE);
\r
4197 RealizePalette(hdc);
\r
4199 HDCDrawPosition(hdc, 1, NULL);
\r
4200 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4201 flipView = !flipView; partnerUp = !partnerUp;
\r
4202 HDCDrawPosition(hdc, 1, NULL);
\r
4203 flipView = !flipView; partnerUp = !partnerUp;
\r
4206 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4207 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4208 ETO_CLIPPED|ETO_OPAQUE,
\r
4209 &messageRect, messageText, strlen(messageText), NULL);
\r
4210 SelectObject(hdc, oldFont);
\r
4211 DisplayBothClocks();
\r
4214 EndPaint(hwnd,&ps);
\r
4222 * If the user selects on a border boundary, return -1; if off the board,
\r
4223 * return -2. Otherwise map the event coordinate to the square.
\r
4224 * The offset boardRect.left or boardRect.top must already have been
\r
4225 * subtracted from x.
\r
4227 int EventToSquare(x, limit)
\r
4232 if (x < lineGap + border)
\r
4234 x -= lineGap + border;
\r
4235 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4237 x /= (squareSize + lineGap);
\r
4249 DropEnable dropEnables[] = {
\r
4250 { 'P', DP_Pawn, N_("Pawn") },
\r
4251 { 'N', DP_Knight, N_("Knight") },
\r
4252 { 'B', DP_Bishop, N_("Bishop") },
\r
4253 { 'R', DP_Rook, N_("Rook") },
\r
4254 { 'Q', DP_Queen, N_("Queen") },
\r
4258 SetupDropMenu(HMENU hmenu)
\r
4260 int i, count, enable;
\r
4262 extern char white_holding[], black_holding[];
\r
4263 char item[MSG_SIZ];
\r
4265 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4266 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4267 dropEnables[i].piece);
\r
4269 while (p && *p++ == dropEnables[i].piece) count++;
\r
4270 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4271 enable = count > 0 || !appData.testLegality
\r
4272 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4273 && !appData.icsActive);
\r
4274 ModifyMenu(hmenu, dropEnables[i].command,
\r
4275 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4276 dropEnables[i].command, item);
\r
4280 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4282 dragInfo.lastpos.x = boardRect.left + x;
\r
4283 dragInfo.lastpos.y = boardRect.top + y;
\r
4284 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4285 dragInfo.from.x = fromX;
\r
4286 dragInfo.from.y = fromY;
\r
4287 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4288 dragInfo.start = dragInfo.from;
\r
4289 SetCapture(hwndMain);
\r
4292 void DragPieceEnd(int x, int y)
\r
4295 dragInfo.start.x = dragInfo.start.y = -1;
\r
4296 dragInfo.from = dragInfo.start;
\r
4297 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4300 void ChangeDragPiece(ChessSquare piece)
\r
4302 dragInfo.piece = piece;
\r
4305 /* Event handler for mouse messages */
\r
4307 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4311 static int recursive = 0;
\r
4313 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4316 if (message == WM_MBUTTONUP) {
\r
4317 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4318 to the middle button: we simulate pressing the left button too!
\r
4320 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4321 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4327 pt.x = LOWORD(lParam);
\r
4328 pt.y = HIWORD(lParam);
\r
4329 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4330 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4331 if (!flipView && y >= 0) {
\r
4332 y = BOARD_HEIGHT - 1 - y;
\r
4334 if (flipView && x >= 0) {
\r
4335 x = BOARD_WIDTH - 1 - x;
\r
4338 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4339 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4341 switch (message) {
\r
4342 case WM_LBUTTONDOWN:
\r
4343 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4344 ClockClick(flipClock); break;
\r
4345 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4346 ClockClick(!flipClock); break;
\r
4348 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4349 dragInfo.start.x = dragInfo.start.y = -1;
\r
4350 dragInfo.from = dragInfo.start;
\r
4352 if(fromX == -1 && frozen) { // not sure where this is for
\r
4353 fromX = fromY = -1;
\r
4354 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4357 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4358 DrawPosition(TRUE, NULL);
\r
4361 case WM_LBUTTONUP:
\r
4362 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4363 DrawPosition(TRUE, NULL);
\r
4366 case WM_MOUSEMOVE:
\r
4367 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4368 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4369 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4370 if ((appData.animateDragging || appData.highlightDragging)
\r
4371 && (wParam & MK_LBUTTON || dragging == 2)
\r
4372 && dragInfo.from.x >= 0)
\r
4374 BOOL full_repaint = FALSE;
\r
4376 if (appData.animateDragging) {
\r
4377 dragInfo.pos = pt;
\r
4379 if (appData.highlightDragging) {
\r
4380 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4381 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4382 full_repaint = TRUE;
\r
4386 DrawPosition( full_repaint, NULL);
\r
4388 dragInfo.lastpos = dragInfo.pos;
\r
4392 case WM_MOUSEWHEEL: // [DM]
\r
4393 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4394 /* Mouse Wheel is being rolled forward
\r
4395 * Play moves forward
\r
4397 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4398 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4399 /* Mouse Wheel is being rolled backward
\r
4400 * Play moves backward
\r
4402 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4403 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4407 case WM_MBUTTONUP:
\r
4408 case WM_RBUTTONUP:
\r
4410 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4413 case WM_MBUTTONDOWN:
\r
4414 case WM_RBUTTONDOWN:
\r
4417 fromX = fromY = -1;
\r
4418 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4419 dragInfo.start.x = dragInfo.start.y = -1;
\r
4420 dragInfo.from = dragInfo.start;
\r
4421 dragInfo.lastpos = dragInfo.pos;
\r
4422 if (appData.highlightDragging) {
\r
4423 ClearHighlights();
\r
4426 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4427 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4428 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4429 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4430 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4434 DrawPosition(TRUE, NULL);
\r
4436 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4439 if (message == WM_MBUTTONDOWN) {
\r
4440 buttonCount = 3; /* even if system didn't think so */
\r
4441 if (wParam & MK_SHIFT)
\r
4442 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4444 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4445 } else { /* message == WM_RBUTTONDOWN */
\r
4446 /* Just have one menu, on the right button. Windows users don't
\r
4447 think to try the middle one, and sometimes other software steals
\r
4448 it, or it doesn't really exist. */
\r
4449 if(gameInfo.variant != VariantShogi)
\r
4450 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4452 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4456 SetCapture(hwndMain);
\r
4459 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4460 SetupDropMenu(hmenu);
\r
4461 MenuPopup(hwnd, pt, hmenu, -1);
\r
4471 /* Preprocess messages for buttons in main window */
\r
4473 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4475 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4478 for (i=0; i<N_BUTTONS; i++) {
\r
4479 if (buttonDesc[i].id == id) break;
\r
4481 if (i == N_BUTTONS) return 0;
\r
4482 switch (message) {
\r
4487 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4488 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4495 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4498 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4499 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4500 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4501 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4503 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4505 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4506 TypeInEvent((char)wParam);
\r
4512 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4515 static int promoStyle;
\r
4517 /* Process messages for Promotion dialog box */
\r
4519 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4524 switch (message) {
\r
4526 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4527 /* Center the dialog over the application window */
\r
4528 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4529 Translate(hDlg, DLG_PromotionKing);
\r
4530 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4531 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4532 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4533 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4534 SW_SHOW : SW_HIDE);
\r
4535 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4536 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4537 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4538 PieceToChar(WhiteAngel) != '~') ||
\r
4539 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4540 PieceToChar(BlackAngel) != '~') ) ?
\r
4541 SW_SHOW : SW_HIDE);
\r
4542 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4543 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4544 PieceToChar(WhiteMarshall) != '~') ||
\r
4545 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4546 PieceToChar(BlackMarshall) != '~') ) ?
\r
4547 SW_SHOW : SW_HIDE);
\r
4548 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4549 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4550 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4552 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4553 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4554 SetWindowText(hDlg, "Promote?");
\r
4556 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4557 gameInfo.variant == VariantSuper ?
\r
4558 SW_SHOW : SW_HIDE);
\r
4561 case WM_COMMAND: /* message: received a command */
\r
4562 switch (LOWORD(wParam)) {
\r
4564 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4565 ClearHighlights();
\r
4566 DrawPosition(FALSE, NULL);
\r
4569 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4572 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4575 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4576 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4579 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4580 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4582 case PB_Chancellor:
\r
4583 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4585 case PB_Archbishop:
\r
4586 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4589 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4590 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4595 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4596 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4597 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4598 fromX = fromY = -1;
\r
4599 if (!appData.highlightLastMove) {
\r
4600 ClearHighlights();
\r
4601 DrawPosition(FALSE, NULL);
\r
4608 /* Pop up promotion dialog */
\r
4610 PromotionPopup(HWND hwnd)
\r
4614 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4615 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4616 hwnd, (DLGPROC)lpProc);
\r
4617 FreeProcInstance(lpProc);
\r
4621 PromotionPopUp(char choice)
\r
4623 promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));
\r
4624 DrawPosition(TRUE, NULL);
\r
4625 PromotionPopup(hwndMain);
\r
4629 LoadGameDialog(HWND hwnd, char* title)
\r
4633 char fileTitle[MSG_SIZ];
\r
4634 f = OpenFileDialog(hwnd, "rb", "",
\r
4635 appData.oldSaveStyle ? "gam" : "pgn",
\r
4637 title, &number, fileTitle, NULL);
\r
4639 cmailMsgLoaded = FALSE;
\r
4640 if (number == 0) {
\r
4641 int error = GameListBuild(f);
\r
4643 DisplayError(_("Cannot build game list"), error);
\r
4644 } else if (!ListEmpty(&gameList) &&
\r
4645 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4646 GameListPopUp(f, fileTitle);
\r
4649 GameListDestroy();
\r
4652 LoadGame(f, number, fileTitle, FALSE);
\r
4656 int get_term_width()
\r
4661 HFONT hfont, hold_font;
\r
4666 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4670 // get the text metrics
\r
4671 hdc = GetDC(hText);
\r
4672 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4673 if (consoleCF.dwEffects & CFE_BOLD)
\r
4674 lf.lfWeight = FW_BOLD;
\r
4675 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4676 lf.lfItalic = TRUE;
\r
4677 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4678 lf.lfStrikeOut = TRUE;
\r
4679 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4680 lf.lfUnderline = TRUE;
\r
4681 hfont = CreateFontIndirect(&lf);
\r
4682 hold_font = SelectObject(hdc, hfont);
\r
4683 GetTextMetrics(hdc, &tm);
\r
4684 SelectObject(hdc, hold_font);
\r
4685 DeleteObject(hfont);
\r
4686 ReleaseDC(hText, hdc);
\r
4688 // get the rectangle
\r
4689 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4691 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4694 void UpdateICSWidth(HWND hText)
\r
4696 LONG old_width, new_width;
\r
4698 new_width = get_term_width(hText, FALSE);
\r
4699 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4700 if (new_width != old_width)
\r
4702 ics_update_width(new_width);
\r
4703 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4708 ChangedConsoleFont()
\r
4711 CHARRANGE tmpsel, sel;
\r
4712 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4713 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4714 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4717 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4718 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4719 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4720 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4721 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4722 * size. This was undocumented in the version of MSVC++ that I had
\r
4723 * when I wrote the code, but is apparently documented now.
\r
4725 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4726 cfmt.bCharSet = f->lf.lfCharSet;
\r
4727 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4728 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4729 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4730 /* Why are the following seemingly needed too? */
\r
4731 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4732 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4733 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4735 tmpsel.cpMax = -1; /*999999?*/
\r
4736 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4737 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4738 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4739 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4741 paraf.cbSize = sizeof(paraf);
\r
4742 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4743 paraf.dxStartIndent = 0;
\r
4744 paraf.dxOffset = WRAP_INDENT;
\r
4745 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4746 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4747 UpdateICSWidth(hText);
\r
4750 /*---------------------------------------------------------------------------*\
\r
4752 * Window Proc for main window
\r
4754 \*---------------------------------------------------------------------------*/
\r
4756 /* Process messages for main window, etc. */
\r
4758 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4765 char fileTitle[MSG_SIZ];
\r
4766 static SnapData sd;
\r
4767 static int peek=0;
\r
4769 switch (message) {
\r
4771 case WM_PAINT: /* message: repaint portion of window */
\r
4775 case WM_ERASEBKGND:
\r
4776 if (IsIconic(hwnd)) {
\r
4777 /* Cheat; change the message */
\r
4778 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4780 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4784 case WM_LBUTTONDOWN:
\r
4785 case WM_MBUTTONDOWN:
\r
4786 case WM_RBUTTONDOWN:
\r
4787 case WM_LBUTTONUP:
\r
4788 case WM_MBUTTONUP:
\r
4789 case WM_RBUTTONUP:
\r
4790 case WM_MOUSEMOVE:
\r
4791 case WM_MOUSEWHEEL:
\r
4792 MouseEvent(hwnd, message, wParam, lParam);
\r
4796 if((char)wParam == '\b') {
\r
4797 ForwardEvent(); peek = 0;
\r
4800 JAWS_KBUP_NAVIGATION
\r
4805 if((char)wParam == '\b') {
\r
4806 if(!peek) BackwardEvent(), peek = 1;
\r
4809 JAWS_KBDOWN_NAVIGATION
\r
4815 JAWS_ALT_INTERCEPT
\r
4817 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4818 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4819 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4820 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4822 SendMessage(h, message, wParam, lParam);
\r
4823 } else if(lParam != KF_REPEAT) {
\r
4824 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4825 TypeInEvent((char)wParam);
\r
4826 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4827 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4832 case WM_PALETTECHANGED:
\r
4833 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4835 HDC hdc = GetDC(hwndMain);
\r
4836 SelectPalette(hdc, hPal, TRUE);
\r
4837 nnew = RealizePalette(hdc);
\r
4839 paletteChanged = TRUE;
\r
4841 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4843 ReleaseDC(hwnd, hdc);
\r
4847 case WM_QUERYNEWPALETTE:
\r
4848 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4850 HDC hdc = GetDC(hwndMain);
\r
4851 paletteChanged = FALSE;
\r
4852 SelectPalette(hdc, hPal, FALSE);
\r
4853 nnew = RealizePalette(hdc);
\r
4855 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4857 ReleaseDC(hwnd, hdc);
\r
4862 case WM_COMMAND: /* message: command from application menu */
\r
4863 wmId = LOWORD(wParam);
\r
4868 SAY("new game enter a move to play against the computer with white");
\r
4871 case IDM_NewGameFRC:
\r
4872 if( NewGameFRC() == 0 ) {
\r
4877 case IDM_NewVariant:
\r
4878 NewVariantPopup(hwnd);
\r
4881 case IDM_LoadGame:
\r
4882 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4885 case IDM_LoadNextGame:
\r
4889 case IDM_LoadPrevGame:
\r
4893 case IDM_ReloadGame:
\r
4897 case IDM_LoadPosition:
\r
4898 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4899 Reset(FALSE, TRUE);
\r
4902 f = OpenFileDialog(hwnd, "rb", "",
\r
4903 appData.oldSaveStyle ? "pos" : "fen",
\r
4905 _("Load Position from File"), &number, fileTitle, NULL);
\r
4907 LoadPosition(f, number, fileTitle);
\r
4911 case IDM_LoadNextPosition:
\r
4912 ReloadPosition(1);
\r
4915 case IDM_LoadPrevPosition:
\r
4916 ReloadPosition(-1);
\r
4919 case IDM_ReloadPosition:
\r
4920 ReloadPosition(0);
\r
4923 case IDM_SaveGame:
\r
4924 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4925 f = OpenFileDialog(hwnd, "a", defName,
\r
4926 appData.oldSaveStyle ? "gam" : "pgn",
\r
4928 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4930 SaveGame(f, 0, "");
\r
4934 case IDM_SavePosition:
\r
4935 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4936 f = OpenFileDialog(hwnd, "a", defName,
\r
4937 appData.oldSaveStyle ? "pos" : "fen",
\r
4939 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4941 SavePosition(f, 0, "");
\r
4945 case IDM_SaveDiagram:
\r
4946 defName = "diagram";
\r
4947 f = OpenFileDialog(hwnd, "wb", defName,
\r
4950 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4956 case IDM_SaveSelected:
\r
4957 f = OpenFileDialog(hwnd, "a", "",
\r
4960 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4962 SaveSelected(f, 0, "");
\r
4966 case IDM_CreateBook:
\r
4967 CreateBookEvent();
\r
4970 case IDM_CopyGame:
\r
4971 CopyGameToClipboard();
\r
4974 case IDM_PasteGame:
\r
4975 PasteGameFromClipboard();
\r
4978 case IDM_CopyGameListToClipboard:
\r
4979 CopyGameListToClipboard();
\r
4982 /* [AS] Autodetect FEN or PGN data */
\r
4983 case IDM_PasteAny:
\r
4984 PasteGameOrFENFromClipboard();
\r
4987 /* [AS] Move history */
\r
4988 case IDM_ShowMoveHistory:
\r
4989 if( MoveHistoryIsUp() ) {
\r
4990 MoveHistoryPopDown();
\r
4993 MoveHistoryPopUp();
\r
4997 /* [AS] Eval graph */
\r
4998 case IDM_ShowEvalGraph:
\r
4999 if( EvalGraphIsUp() ) {
\r
5000 EvalGraphPopDown();
\r
5004 SetFocus(hwndMain);
\r
5008 /* [AS] Engine output */
\r
5009 case IDM_ShowEngineOutput:
\r
5010 if( EngineOutputIsUp() ) {
\r
5011 EngineOutputPopDown();
\r
5014 EngineOutputPopUp();
\r
5018 /* [AS] User adjudication */
\r
5019 case IDM_UserAdjudication_White:
\r
5020 UserAdjudicationEvent( +1 );
\r
5023 case IDM_UserAdjudication_Black:
\r
5024 UserAdjudicationEvent( -1 );
\r
5027 case IDM_UserAdjudication_Draw:
\r
5028 UserAdjudicationEvent( 0 );
\r
5031 /* [AS] Game list options dialog */
\r
5032 case IDM_GameListOptions:
\r
5033 GameListOptions();
\r
5040 case IDM_CopyPosition:
\r
5041 CopyFENToClipboard();
\r
5044 case IDM_PastePosition:
\r
5045 PasteFENFromClipboard();
\r
5048 case IDM_MailMove:
\r
5052 case IDM_ReloadCMailMsg:
\r
5053 Reset(TRUE, TRUE);
\r
5054 ReloadCmailMsgEvent(FALSE);
\r
5057 case IDM_Minimize:
\r
5058 ShowWindow(hwnd, SW_MINIMIZE);
\r
5065 case IDM_MachineWhite:
\r
5066 MachineWhiteEvent();
\r
5068 * refresh the tags dialog only if it's visible
\r
5070 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5072 tags = PGNTags(&gameInfo);
\r
5073 TagsPopUp(tags, CmailMsg());
\r
5076 SAY("computer starts playing white");
\r
5079 case IDM_MachineBlack:
\r
5080 MachineBlackEvent();
\r
5082 * refresh the tags dialog only if it's visible
\r
5084 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5086 tags = PGNTags(&gameInfo);
\r
5087 TagsPopUp(tags, CmailMsg());
\r
5090 SAY("computer starts playing black");
\r
5093 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5094 if(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED);
\r
5095 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5098 case IDM_TwoMachines:
\r
5099 TwoMachinesEvent();
\r
5102 * refresh the tags dialog only if it's visible
\r
5104 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5106 tags = PGNTags(&gameInfo);
\r
5107 TagsPopUp(tags, CmailMsg());
\r
5110 SAY("computer starts playing both sides");
\r
5113 case IDM_AnalysisMode:
\r
5114 if(AnalyzeModeEvent()) {
\r
5115 SAY("analyzing current position");
\r
5119 case IDM_AnalyzeFile:
\r
5120 AnalyzeFileEvent();
\r
5123 case IDM_IcsClient:
\r
5127 case IDM_EditGame:
\r
5128 case IDM_EditGame2:
\r
5133 case IDM_EditPosition:
\r
5134 case IDM_EditPosition2:
\r
5135 EditPositionEvent();
\r
5136 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5139 case IDM_Training:
\r
5143 case IDM_ShowGameList:
\r
5144 ShowGameListProc();
\r
5147 case IDM_EditProgs1:
\r
5148 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5151 case IDM_LoadProg1:
\r
5152 LoadEnginePopUp(hwndMain, 0);
\r
5155 case IDM_LoadProg2:
\r
5156 LoadEnginePopUp(hwndMain, 1);
\r
5159 case IDM_EditServers:
\r
5160 EditTagsPopUp(icsNames, &icsNames);
\r
5163 case IDM_EditTags:
\r
5168 case IDM_EditBook:
\r
5172 case IDM_EditComment:
\r
5174 if (commentUp && editComment) {
\r
5177 EditCommentEvent();
\r
5198 case IDM_CallFlag:
\r
5218 case IDM_StopObserving:
\r
5219 StopObservingEvent();
\r
5222 case IDM_StopExamining:
\r
5223 StopExaminingEvent();
\r
5227 UploadGameEvent();
\r
5230 case IDM_TypeInMove:
\r
5231 TypeInEvent('\000');
\r
5234 case IDM_TypeInName:
\r
5235 PopUpNameDialog('\000');
\r
5238 case IDM_Backward:
\r
5240 SetFocus(hwndMain);
\r
5247 SetFocus(hwndMain);
\r
5252 SetFocus(hwndMain);
\r
5257 SetFocus(hwndMain);
\r
5260 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5261 case OPT_GameListPrev:
\r
5262 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5266 RevertEvent(FALSE);
\r
5269 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5270 RevertEvent(TRUE);
\r
5273 case IDM_TruncateGame:
\r
5274 TruncateGameEvent();
\r
5281 case IDM_RetractMove:
\r
5282 RetractMoveEvent();
\r
5285 case IDM_FlipView:
\r
5286 flipView = !flipView;
\r
5287 DrawPosition(FALSE, NULL);
\r
5290 case IDM_FlipClock:
\r
5291 flipClock = !flipClock;
\r
5292 DisplayBothClocks();
\r
5296 case IDM_MuteSounds:
\r
5297 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5298 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5299 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5302 case IDM_GeneralOptions:
\r
5303 GeneralOptionsPopup(hwnd);
\r
5304 DrawPosition(TRUE, NULL);
\r
5307 case IDM_BoardOptions:
\r
5308 BoardOptionsPopup(hwnd);
\r
5311 case IDM_ThemeOptions:
\r
5312 ThemeOptionsPopup(hwnd);
\r
5315 case IDM_EnginePlayOptions:
\r
5316 EnginePlayOptionsPopup(hwnd);
\r
5319 case IDM_Engine1Options:
\r
5320 EngineOptionsPopup(hwnd, &first);
\r
5323 case IDM_Engine2Options:
\r
5325 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5326 EngineOptionsPopup(hwnd, &second);
\r
5329 case IDM_OptionsUCI:
\r
5330 UciOptionsPopup(hwnd);
\r
5334 TourneyPopup(hwnd);
\r
5337 case IDM_IcsOptions:
\r
5338 IcsOptionsPopup(hwnd);
\r
5342 FontsOptionsPopup(hwnd);
\r
5346 SoundOptionsPopup(hwnd);
\r
5349 case IDM_CommPort:
\r
5350 CommPortOptionsPopup(hwnd);
\r
5353 case IDM_LoadOptions:
\r
5354 LoadOptionsPopup(hwnd);
\r
5357 case IDM_SaveOptions:
\r
5358 SaveOptionsPopup(hwnd);
\r
5361 case IDM_TimeControl:
\r
5362 TimeControlOptionsPopup(hwnd);
\r
5365 case IDM_SaveSettings:
\r
5366 SaveSettings(settingsFileName);
\r
5369 case IDM_SaveSettingsOnExit:
\r
5370 saveSettingsOnExit = !saveSettingsOnExit;
\r
5371 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5372 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5373 MF_CHECKED : MF_UNCHECKED));
\r
5384 case IDM_AboutGame:
\r
5389 appData.debugMode = !appData.debugMode;
\r
5390 if (appData.debugMode) {
\r
5391 char dir[MSG_SIZ];
\r
5392 GetCurrentDirectory(MSG_SIZ, dir);
\r
5393 SetCurrentDirectory(installDir);
\r
5394 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5395 SetCurrentDirectory(dir);
\r
5396 setbuf(debugFP, NULL);
\r
5403 case IDM_HELPCONTENTS:
\r
5404 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5405 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5406 MessageBox (GetFocus(),
\r
5407 _("Unable to activate help"),
\r
5408 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5412 case IDM_HELPSEARCH:
\r
5413 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5414 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5415 MessageBox (GetFocus(),
\r
5416 _("Unable to activate help"),
\r
5417 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5421 case IDM_HELPHELP:
\r
5422 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5423 MessageBox (GetFocus(),
\r
5424 _("Unable to activate help"),
\r
5425 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5430 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5432 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5433 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5434 FreeProcInstance(lpProc);
\r
5437 case IDM_DirectCommand1:
\r
5438 AskQuestionEvent(_("Direct Command"),
\r
5439 _("Send to chess program:"), "", "1");
\r
5441 case IDM_DirectCommand2:
\r
5442 AskQuestionEvent(_("Direct Command"),
\r
5443 _("Send to second chess program:"), "", "2");
\r
5446 case EP_WhitePawn:
\r
5447 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5448 fromX = fromY = -1;
\r
5451 case EP_WhiteKnight:
\r
5452 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5453 fromX = fromY = -1;
\r
5456 case EP_WhiteBishop:
\r
5457 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5458 fromX = fromY = -1;
\r
5461 case EP_WhiteRook:
\r
5462 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5463 fromX = fromY = -1;
\r
5466 case EP_WhiteQueen:
\r
5467 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5468 fromX = fromY = -1;
\r
5471 case EP_WhiteFerz:
\r
5472 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5473 fromX = fromY = -1;
\r
5476 case EP_WhiteWazir:
\r
5477 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5478 fromX = fromY = -1;
\r
5481 case EP_WhiteAlfil:
\r
5482 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5483 fromX = fromY = -1;
\r
5486 case EP_WhiteCannon:
\r
5487 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5488 fromX = fromY = -1;
\r
5491 case EP_WhiteCardinal:
\r
5492 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5493 fromX = fromY = -1;
\r
5496 case EP_WhiteMarshall:
\r
5497 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5498 fromX = fromY = -1;
\r
5501 case EP_WhiteKing:
\r
5502 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5503 fromX = fromY = -1;
\r
5506 case EP_BlackPawn:
\r
5507 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5508 fromX = fromY = -1;
\r
5511 case EP_BlackKnight:
\r
5512 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5513 fromX = fromY = -1;
\r
5516 case EP_BlackBishop:
\r
5517 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5518 fromX = fromY = -1;
\r
5521 case EP_BlackRook:
\r
5522 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5523 fromX = fromY = -1;
\r
5526 case EP_BlackQueen:
\r
5527 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5528 fromX = fromY = -1;
\r
5531 case EP_BlackFerz:
\r
5532 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5533 fromX = fromY = -1;
\r
5536 case EP_BlackWazir:
\r
5537 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5538 fromX = fromY = -1;
\r
5541 case EP_BlackAlfil:
\r
5542 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5543 fromX = fromY = -1;
\r
5546 case EP_BlackCannon:
\r
5547 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5548 fromX = fromY = -1;
\r
5551 case EP_BlackCardinal:
\r
5552 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5553 fromX = fromY = -1;
\r
5556 case EP_BlackMarshall:
\r
5557 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5558 fromX = fromY = -1;
\r
5561 case EP_BlackKing:
\r
5562 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5563 fromX = fromY = -1;
\r
5566 case EP_EmptySquare:
\r
5567 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5568 fromX = fromY = -1;
\r
5571 case EP_ClearBoard:
\r
5572 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5573 fromX = fromY = -1;
\r
5577 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5578 fromX = fromY = -1;
\r
5582 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5583 fromX = fromY = -1;
\r
5587 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5588 fromX = fromY = -1;
\r
5592 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5593 fromX = fromY = -1;
\r
5597 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5598 fromX = fromY = -1;
\r
5602 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5603 fromX = fromY = -1;
\r
5607 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5608 fromX = fromY = -1;
\r
5612 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5613 fromX = fromY = -1;
\r
5617 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5618 fromX = fromY = -1;
\r
5622 barbaric = 0; appData.language = "";
\r
5623 TranslateMenus(0);
\r
5624 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5625 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5626 lastChecked = wmId;
\r
5630 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5631 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5633 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5634 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5635 TranslateMenus(0);
\r
5636 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5637 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5638 lastChecked = wmId;
\r
5641 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5647 case CLOCK_TIMER_ID:
\r
5648 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5649 clockTimerEvent = 0;
\r
5650 DecrementClocks(); /* call into back end */
\r
5652 case LOAD_GAME_TIMER_ID:
\r
5653 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5654 loadGameTimerEvent = 0;
\r
5655 AutoPlayGameLoop(); /* call into back end */
\r
5657 case ANALYSIS_TIMER_ID:
\r
5658 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5659 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5660 AnalysisPeriodicEvent(0);
\r
5662 KillTimer(hwnd, analysisTimerEvent);
\r
5663 analysisTimerEvent = 0;
\r
5666 case DELAYED_TIMER_ID:
\r
5667 KillTimer(hwnd, delayedTimerEvent);
\r
5668 delayedTimerEvent = 0;
\r
5669 delayedTimerCallback();
\r
5674 case WM_USER_Input:
\r
5675 InputEvent(hwnd, message, wParam, lParam);
\r
5678 /* [AS] Also move "attached" child windows */
\r
5679 case WM_WINDOWPOSCHANGING:
\r
5681 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5682 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5684 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5685 /* Window is moving */
\r
5688 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5689 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5690 rcMain.right = wpMain.x + wpMain.width;
\r
5691 rcMain.top = wpMain.y;
\r
5692 rcMain.bottom = wpMain.y + wpMain.height;
\r
5694 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5695 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5696 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5697 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5698 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5699 wpMain.x = lpwp->x;
\r
5700 wpMain.y = lpwp->y;
\r
5705 /* [AS] Snapping */
\r
5706 case WM_ENTERSIZEMOVE:
\r
5707 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5708 if (hwnd == hwndMain) {
\r
5709 doingSizing = TRUE;
\r
5712 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5716 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5717 if (hwnd == hwndMain) {
\r
5718 lastSizing = wParam;
\r
5723 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5724 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5726 case WM_EXITSIZEMOVE:
\r
5727 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5728 if (hwnd == hwndMain) {
\r
5730 doingSizing = FALSE;
\r
5731 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5732 GetClientRect(hwnd, &client);
\r
5733 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5735 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5737 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5740 case WM_DESTROY: /* message: window being destroyed */
\r
5741 PostQuitMessage(0);
\r
5745 if (hwnd == hwndMain) {
\r
5750 default: /* Passes it on if unprocessed */
\r
5751 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5758 /*---------------------------------------------------------------------------*\
\r
5760 * Misc utility routines
\r
5762 \*---------------------------------------------------------------------------*/
\r
5765 * Decent random number generator, at least not as bad as Windows
\r
5766 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5768 unsigned int randstate;
\r
5773 randstate = randstate * 1664525 + 1013904223;
\r
5774 return (int) randstate & 0x7fffffff;
\r
5778 mysrandom(unsigned int seed)
\r
5785 * returns TRUE if user selects a different color, FALSE otherwise
\r
5789 ChangeColor(HWND hwnd, COLORREF *which)
\r
5791 static BOOL firstTime = TRUE;
\r
5792 static DWORD customColors[16];
\r
5794 COLORREF newcolor;
\r
5799 /* Make initial colors in use available as custom colors */
\r
5800 /* Should we put the compiled-in defaults here instead? */
\r
5802 customColors[i++] = lightSquareColor & 0xffffff;
\r
5803 customColors[i++] = darkSquareColor & 0xffffff;
\r
5804 customColors[i++] = whitePieceColor & 0xffffff;
\r
5805 customColors[i++] = blackPieceColor & 0xffffff;
\r
5806 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5807 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5809 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5810 customColors[i++] = textAttribs[ccl].color;
\r
5812 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5813 firstTime = FALSE;
\r
5816 cc.lStructSize = sizeof(cc);
\r
5817 cc.hwndOwner = hwnd;
\r
5818 cc.hInstance = NULL;
\r
5819 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5820 cc.lpCustColors = (LPDWORD) customColors;
\r
5821 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5823 if (!ChooseColor(&cc)) return FALSE;
\r
5825 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5826 if (newcolor == *which) return FALSE;
\r
5827 *which = newcolor;
\r
5831 InitDrawingColors();
\r
5832 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5837 MyLoadSound(MySound *ms)
\r
5843 if (ms->data && ms->flag) free(ms->data);
\r
5846 switch (ms->name[0]) {
\r
5852 /* System sound from Control Panel. Don't preload here. */
\r
5856 if (ms->name[1] == NULLCHAR) {
\r
5857 /* "!" alone = silence */
\r
5860 /* Builtin wave resource. Error if not found. */
\r
5861 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5862 if (h == NULL) break;
\r
5863 ms->data = (void *)LoadResource(hInst, h);
\r
5864 ms->flag = 0; // not maloced, so cannot be freed!
\r
5865 if (h == NULL) break;
\r
5870 /* .wav file. Error if not found. */
\r
5871 f = fopen(ms->name, "rb");
\r
5872 if (f == NULL) break;
\r
5873 if (fstat(fileno(f), &st) < 0) break;
\r
5874 ms->data = malloc(st.st_size);
\r
5876 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5882 char buf[MSG_SIZ];
\r
5883 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5884 DisplayError(buf, GetLastError());
\r
5890 MyPlaySound(MySound *ms)
\r
5892 BOOLEAN ok = FALSE;
\r
5894 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5895 switch (ms->name[0]) {
\r
5897 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5902 /* System sound from Control Panel (deprecated feature).
\r
5903 "$" alone or an unset sound name gets default beep (still in use). */
\r
5904 if (ms->name[1]) {
\r
5905 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5907 if (!ok) ok = MessageBeep(MB_OK);
\r
5910 /* Builtin wave resource, or "!" alone for silence */
\r
5911 if (ms->name[1]) {
\r
5912 if (ms->data == NULL) return FALSE;
\r
5913 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5919 /* .wav file. Error if not found. */
\r
5920 if (ms->data == NULL) return FALSE;
\r
5921 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5924 /* Don't print an error: this can happen innocently if the sound driver
\r
5925 is busy; for instance, if another instance of WinBoard is playing
\r
5926 a sound at about the same time. */
\r
5932 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5935 OPENFILENAME *ofn;
\r
5936 static UINT *number; /* gross that this is static */
\r
5938 switch (message) {
\r
5939 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5940 /* Center the dialog over the application window */
\r
5941 ofn = (OPENFILENAME *) lParam;
\r
5942 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5943 number = (UINT *) ofn->lCustData;
\r
5944 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5948 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5949 Translate(hDlg, 1536);
\r
5950 return FALSE; /* Allow for further processing */
\r
5953 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5954 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5956 return FALSE; /* Allow for further processing */
\r
5962 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5964 static UINT *number;
\r
5965 OPENFILENAME *ofname;
\r
5968 case WM_INITDIALOG:
\r
5969 Translate(hdlg, DLG_IndexNumber);
\r
5970 ofname = (OPENFILENAME *)lParam;
\r
5971 number = (UINT *)(ofname->lCustData);
\r
5974 ofnot = (OFNOTIFY *)lParam;
\r
5975 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5976 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5985 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5986 char *nameFilt, char *dlgTitle, UINT *number,
\r
5987 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5989 OPENFILENAME openFileName;
\r
5990 char buf1[MSG_SIZ];
\r
5993 if (fileName == NULL) fileName = buf1;
\r
5994 if (defName == NULL) {
\r
5995 safeStrCpy(fileName, "*.", 3 );
\r
5996 strcat(fileName, defExt);
\r
5998 safeStrCpy(fileName, defName, MSG_SIZ );
\r
6000 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
6001 if (number) *number = 0;
\r
6003 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6004 openFileName.hwndOwner = hwnd;
\r
6005 openFileName.hInstance = (HANDLE) hInst;
\r
6006 openFileName.lpstrFilter = nameFilt;
\r
6007 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6008 openFileName.nMaxCustFilter = 0L;
\r
6009 openFileName.nFilterIndex = 1L;
\r
6010 openFileName.lpstrFile = fileName;
\r
6011 openFileName.nMaxFile = MSG_SIZ;
\r
6012 openFileName.lpstrFileTitle = fileTitle;
\r
6013 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6014 openFileName.lpstrInitialDir = NULL;
\r
6015 openFileName.lpstrTitle = dlgTitle;
\r
6016 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6017 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6018 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6019 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6020 openFileName.nFileOffset = 0;
\r
6021 openFileName.nFileExtension = 0;
\r
6022 openFileName.lpstrDefExt = defExt;
\r
6023 openFileName.lCustData = (LONG) number;
\r
6024 openFileName.lpfnHook = oldDialog ?
\r
6025 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6026 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6028 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6029 GetOpenFileName(&openFileName)) {
\r
6030 /* open the file */
\r
6031 f = fopen(openFileName.lpstrFile, write);
\r
6033 MessageBox(hwnd, _("File open failed"), NULL,
\r
6034 MB_OK|MB_ICONEXCLAMATION);
\r
6038 int err = CommDlgExtendedError();
\r
6039 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6048 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6050 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6053 * Get the first pop-up menu in the menu template. This is the
\r
6054 * menu that TrackPopupMenu displays.
\r
6056 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6057 TranslateOneMenu(10, hmenuTrackPopup);
\r
6059 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6062 * TrackPopup uses screen coordinates, so convert the
\r
6063 * coordinates of the mouse click to screen coordinates.
\r
6065 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6067 /* Draw and track the floating pop-up menu. */
\r
6068 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6069 pt.x, pt.y, 0, hwnd, NULL);
\r
6071 /* Destroy the menu.*/
\r
6072 DestroyMenu(hmenu);
\r
6077 int sizeX, sizeY, newSizeX, newSizeY;
\r
6079 } ResizeEditPlusButtonsClosure;
\r
6082 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6084 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6088 if (hChild == cl->hText) return TRUE;
\r
6089 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6090 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6091 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6092 ScreenToClient(cl->hDlg, &pt);
\r
6093 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6094 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6098 /* Resize a dialog that has a (rich) edit field filling most of
\r
6099 the top, with a row of buttons below */
\r
6101 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6104 int newTextHeight, newTextWidth;
\r
6105 ResizeEditPlusButtonsClosure cl;
\r
6107 /*if (IsIconic(hDlg)) return;*/
\r
6108 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6110 cl.hdwp = BeginDeferWindowPos(8);
\r
6112 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6113 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6114 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6115 if (newTextHeight < 0) {
\r
6116 newSizeY += -newTextHeight;
\r
6117 newTextHeight = 0;
\r
6119 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6120 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6126 cl.newSizeX = newSizeX;
\r
6127 cl.newSizeY = newSizeY;
\r
6128 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6130 EndDeferWindowPos(cl.hdwp);
\r
6133 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6135 RECT rChild, rParent;
\r
6136 int wChild, hChild, wParent, hParent;
\r
6137 int wScreen, hScreen, xNew, yNew;
\r
6140 /* Get the Height and Width of the child window */
\r
6141 GetWindowRect (hwndChild, &rChild);
\r
6142 wChild = rChild.right - rChild.left;
\r
6143 hChild = rChild.bottom - rChild.top;
\r
6145 /* Get the Height and Width of the parent window */
\r
6146 GetWindowRect (hwndParent, &rParent);
\r
6147 wParent = rParent.right - rParent.left;
\r
6148 hParent = rParent.bottom - rParent.top;
\r
6150 /* Get the display limits */
\r
6151 hdc = GetDC (hwndChild);
\r
6152 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6153 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6154 ReleaseDC(hwndChild, hdc);
\r
6156 /* Calculate new X position, then adjust for screen */
\r
6157 xNew = rParent.left + ((wParent - wChild) /2);
\r
6160 } else if ((xNew+wChild) > wScreen) {
\r
6161 xNew = wScreen - wChild;
\r
6164 /* Calculate new Y position, then adjust for screen */
\r
6166 yNew = rParent.top + ((hParent - hChild) /2);
\r
6169 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6174 } else if ((yNew+hChild) > hScreen) {
\r
6175 yNew = hScreen - hChild;
\r
6178 /* Set it, and return */
\r
6179 return SetWindowPos (hwndChild, NULL,
\r
6180 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6183 /* Center one window over another */
\r
6184 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6186 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6189 /*---------------------------------------------------------------------------*\
\r
6191 * Startup Dialog functions
\r
6193 \*---------------------------------------------------------------------------*/
\r
6195 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6197 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6199 while (*cd != NULL) {
\r
6200 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6206 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6208 char buf1[MAX_ARG_LEN];
\r
6211 if (str[0] == '@') {
\r
6212 FILE* f = fopen(str + 1, "r");
\r
6214 DisplayFatalError(str + 1, errno, 2);
\r
6217 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6219 buf1[len] = NULLCHAR;
\r
6223 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6226 char buf[MSG_SIZ];
\r
6227 char *end = strchr(str, '\n');
\r
6228 if (end == NULL) return;
\r
6229 memcpy(buf, str, end - str);
\r
6230 buf[end - str] = NULLCHAR;
\r
6231 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6237 SetStartupDialogEnables(HWND hDlg)
\r
6239 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6240 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6241 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6242 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6243 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6244 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6245 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6246 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6247 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6248 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6249 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6250 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6251 IsDlgButtonChecked(hDlg, OPT_View));
\r
6255 QuoteForFilename(char *filename)
\r
6257 int dquote, space;
\r
6258 dquote = strchr(filename, '"') != NULL;
\r
6259 space = strchr(filename, ' ') != NULL;
\r
6260 if (dquote || space) {
\r
6272 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6274 char buf[MSG_SIZ];
\r
6277 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6278 q = QuoteForFilename(nthcp);
\r
6279 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6280 if (*nthdir != NULLCHAR) {
\r
6281 q = QuoteForFilename(nthdir);
\r
6282 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6284 if (*nthcp == NULLCHAR) {
\r
6285 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6286 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6287 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6288 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6293 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6295 char buf[MSG_SIZ];
\r
6299 switch (message) {
\r
6300 case WM_INITDIALOG:
\r
6301 /* Center the dialog */
\r
6302 CenterWindow (hDlg, GetDesktopWindow());
\r
6303 Translate(hDlg, DLG_Startup);
\r
6304 /* Initialize the dialog items */
\r
6305 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6306 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6307 firstChessProgramNames);
\r
6308 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6309 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6310 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6311 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6312 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6313 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6314 if (*appData.icsHelper != NULLCHAR) {
\r
6315 char *q = QuoteForFilename(appData.icsHelper);
\r
6316 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6318 if (*appData.icsHost == NULLCHAR) {
\r
6319 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6320 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6321 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6322 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6323 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6326 if (appData.icsActive) {
\r
6327 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6329 else if (appData.noChessProgram) {
\r
6330 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6333 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6336 SetStartupDialogEnables(hDlg);
\r
6340 switch (LOWORD(wParam)) {
\r
6342 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6343 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6344 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6346 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6347 ParseArgs(StringGet, &p);
\r
6348 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6349 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6351 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6352 ParseArgs(StringGet, &p);
\r
6353 SwapEngines(singleList); // ... and then make it 'second'
\r
6355 appData.noChessProgram = FALSE;
\r
6356 appData.icsActive = FALSE;
\r
6357 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6358 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6359 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6361 ParseArgs(StringGet, &p);
\r
6362 if (appData.zippyPlay) {
\r
6363 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6364 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6366 ParseArgs(StringGet, &p);
\r
6368 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6369 appData.noChessProgram = TRUE;
\r
6370 appData.icsActive = FALSE;
\r
6372 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6373 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6376 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6377 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6379 ParseArgs(StringGet, &p);
\r
6381 EndDialog(hDlg, TRUE);
\r
6388 case IDM_HELPCONTENTS:
\r
6389 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6390 MessageBox (GetFocus(),
\r
6391 _("Unable to activate help"),
\r
6392 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6397 SetStartupDialogEnables(hDlg);
\r
6405 /*---------------------------------------------------------------------------*\
\r
6407 * About box dialog functions
\r
6409 \*---------------------------------------------------------------------------*/
\r
6411 /* Process messages for "About" dialog box */
\r
6413 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6415 switch (message) {
\r
6416 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6417 /* Center the dialog over the application window */
\r
6418 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6419 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6420 Translate(hDlg, ABOUTBOX);
\r
6424 case WM_COMMAND: /* message: received a command */
\r
6425 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6426 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6427 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6435 /*---------------------------------------------------------------------------*\
\r
6437 * Comment Dialog functions
\r
6439 \*---------------------------------------------------------------------------*/
\r
6442 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6444 static HANDLE hwndText = NULL;
\r
6445 int len, newSizeX, newSizeY;
\r
6446 static int sizeX, sizeY;
\r
6451 switch (message) {
\r
6452 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6453 /* Initialize the dialog items */
\r
6454 Translate(hDlg, DLG_EditComment);
\r
6455 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6456 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6457 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6458 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6459 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6460 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6461 SetWindowText(hDlg, commentTitle);
\r
6462 if (editComment) {
\r
6463 SetFocus(hwndText);
\r
6465 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6467 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6468 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6469 MAKELPARAM(FALSE, 0));
\r
6470 /* Size and position the dialog */
\r
6471 if (!commentDialog) {
\r
6472 commentDialog = hDlg;
\r
6473 GetClientRect(hDlg, &rect);
\r
6474 sizeX = rect.right;
\r
6475 sizeY = rect.bottom;
\r
6476 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6477 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6478 WINDOWPLACEMENT wp;
\r
6479 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6480 wp.length = sizeof(WINDOWPLACEMENT);
\r
6482 wp.showCmd = SW_SHOW;
\r
6483 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6484 wp.rcNormalPosition.left = wpComment.x;
\r
6485 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6486 wp.rcNormalPosition.top = wpComment.y;
\r
6487 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6488 SetWindowPlacement(hDlg, &wp);
\r
6490 GetClientRect(hDlg, &rect);
\r
6491 newSizeX = rect.right;
\r
6492 newSizeY = rect.bottom;
\r
6493 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6494 newSizeX, newSizeY);
\r
6499 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6502 case WM_COMMAND: /* message: received a command */
\r
6503 switch (LOWORD(wParam)) {
\r
6505 if (editComment) {
\r
6507 /* Read changed options from the dialog box */
\r
6508 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6509 len = GetWindowTextLength(hwndText);
\r
6510 str = (char *) malloc(len + 1);
\r
6511 GetWindowText(hwndText, str, len + 1);
\r
6520 ReplaceComment(commentIndex, str);
\r
6527 case OPT_CancelComment:
\r
6531 case OPT_ClearComment:
\r
6532 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6535 case OPT_EditComment:
\r
6536 EditCommentEvent();
\r
6544 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6545 if( wParam == OPT_CommentText ) {
\r
6546 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6548 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6549 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6553 pt.x = LOWORD( lpMF->lParam );
\r
6554 pt.y = HIWORD( lpMF->lParam );
\r
6556 if(lpMF->msg == WM_CHAR) {
\r
6558 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6559 index = sel.cpMin;
\r
6561 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6563 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6564 len = GetWindowTextLength(hwndText);
\r
6565 str = (char *) malloc(len + 1);
\r
6566 GetWindowText(hwndText, str, len + 1);
\r
6567 ReplaceComment(commentIndex, str);
\r
6568 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6569 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6572 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6573 lpMF->msg = WM_USER;
\r
6581 newSizeX = LOWORD(lParam);
\r
6582 newSizeY = HIWORD(lParam);
\r
6583 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6588 case WM_GETMINMAXINFO:
\r
6589 /* Prevent resizing window too small */
\r
6590 mmi = (MINMAXINFO *) lParam;
\r
6591 mmi->ptMinTrackSize.x = 100;
\r
6592 mmi->ptMinTrackSize.y = 100;
\r
6599 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6604 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6606 if (str == NULL) str = "";
\r
6607 p = (char *) malloc(2 * strlen(str) + 2);
\r
6610 if (*str == '\n') *q++ = '\r';
\r
6614 if (commentText != NULL) free(commentText);
\r
6616 commentIndex = index;
\r
6617 commentTitle = title;
\r
6619 editComment = edit;
\r
6621 if (commentDialog) {
\r
6622 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6623 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6625 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6626 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6627 hwndMain, (DLGPROC)lpProc);
\r
6628 FreeProcInstance(lpProc);
\r
6634 /*---------------------------------------------------------------------------*\
\r
6636 * Type-in move dialog functions
\r
6638 \*---------------------------------------------------------------------------*/
\r
6641 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6643 char move[MSG_SIZ];
\r
6646 switch (message) {
\r
6647 case WM_INITDIALOG:
\r
6648 move[0] = (char) lParam;
\r
6649 move[1] = NULLCHAR;
\r
6650 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6651 Translate(hDlg, DLG_TypeInMove);
\r
6652 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6653 SetWindowText(hInput, move);
\r
6655 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6659 switch (LOWORD(wParam)) {
\r
6662 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6663 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6664 TypeInDoneEvent(move);
\r
6665 EndDialog(hDlg, TRUE);
\r
6668 EndDialog(hDlg, FALSE);
\r
6679 PopUpMoveDialog(char firstchar)
\r
6683 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6684 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6685 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6686 FreeProcInstance(lpProc);
\r
6689 /*---------------------------------------------------------------------------*\
\r
6691 * Type-in name dialog functions
\r
6693 \*---------------------------------------------------------------------------*/
\r
6696 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6698 char move[MSG_SIZ];
\r
6701 switch (message) {
\r
6702 case WM_INITDIALOG:
\r
6703 move[0] = (char) lParam;
\r
6704 move[1] = NULLCHAR;
\r
6705 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6706 Translate(hDlg, DLG_TypeInName);
\r
6707 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6708 SetWindowText(hInput, move);
\r
6710 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6714 switch (LOWORD(wParam)) {
\r
6716 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6717 appData.userName = strdup(move);
\r
6720 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6721 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6722 DisplayTitle(move);
\r
6726 EndDialog(hDlg, TRUE);
\r
6729 EndDialog(hDlg, FALSE);
\r
6740 PopUpNameDialog(char firstchar)
\r
6744 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6745 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6746 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6747 FreeProcInstance(lpProc);
\r
6750 /*---------------------------------------------------------------------------*\
\r
6754 \*---------------------------------------------------------------------------*/
\r
6756 /* Nonmodal error box */
\r
6757 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6758 WPARAM wParam, LPARAM lParam);
\r
6761 ErrorPopUp(char *title, char *content)
\r
6765 BOOLEAN modal = hwndMain == NULL;
\r
6783 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6784 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6787 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6789 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6790 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6791 hwndMain, (DLGPROC)lpProc);
\r
6792 FreeProcInstance(lpProc);
\r
6799 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6800 if (errorDialog == NULL) return;
\r
6801 DestroyWindow(errorDialog);
\r
6802 errorDialog = NULL;
\r
6803 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6807 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6811 switch (message) {
\r
6812 case WM_INITDIALOG:
\r
6813 GetWindowRect(hDlg, &rChild);
\r
6816 SetWindowPos(hDlg, NULL, rChild.left,
\r
6817 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6818 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6822 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6823 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6824 and it doesn't work when you resize the dialog.
\r
6825 For now, just give it a default position.
\r
6827 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6828 Translate(hDlg, DLG_Error);
\r
6830 errorDialog = hDlg;
\r
6831 SetWindowText(hDlg, errorTitle);
\r
6832 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6836 switch (LOWORD(wParam)) {
\r
6839 if (errorDialog == hDlg) errorDialog = NULL;
\r
6840 DestroyWindow(hDlg);
\r
6852 HWND gothicDialog = NULL;
\r
6855 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6858 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6860 switch (message) {
\r
6861 case WM_INITDIALOG:
\r
6862 GetWindowRect(hDlg, &rChild);
\r
6864 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6868 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6869 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6870 and it doesn't work when you resize the dialog.
\r
6871 For now, just give it a default position.
\r
6873 gothicDialog = hDlg;
\r
6874 SetWindowText(hDlg, errorTitle);
\r
6875 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6879 switch (LOWORD(wParam)) {
\r
6882 if (errorDialog == hDlg) errorDialog = NULL;
\r
6883 DestroyWindow(hDlg);
\r
6895 GothicPopUp(char *title, VariantClass variant)
\r
6898 static char *lastTitle;
\r
6900 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6901 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6903 if(lastTitle != title && gothicDialog != NULL) {
\r
6904 DestroyWindow(gothicDialog);
\r
6905 gothicDialog = NULL;
\r
6907 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6908 title = lastTitle;
\r
6909 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6910 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6911 hwndMain, (DLGPROC)lpProc);
\r
6912 FreeProcInstance(lpProc);
\r
6917 /*---------------------------------------------------------------------------*\
\r
6919 * Ics Interaction console functions
\r
6921 \*---------------------------------------------------------------------------*/
\r
6923 #define HISTORY_SIZE 64
\r
6924 static char *history[HISTORY_SIZE];
\r
6925 int histIn = 0, histP = 0;
\r
6929 SaveInHistory(char *cmd)
\r
6931 if (history[histIn] != NULL) {
\r
6932 free(history[histIn]);
\r
6933 history[histIn] = NULL;
\r
6935 if (*cmd == NULLCHAR) return;
\r
6936 history[histIn] = StrSave(cmd);
\r
6937 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6938 if (history[histIn] != NULL) {
\r
6939 free(history[histIn]);
\r
6941 history[histIn] = NULL;
\r
6947 PrevInHistory(char *cmd)
\r
6950 if (histP == histIn) {
\r
6951 if (history[histIn] != NULL) free(history[histIn]);
\r
6952 history[histIn] = StrSave(cmd);
\r
6954 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6955 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6957 return history[histP];
\r
6963 if (histP == histIn) return NULL;
\r
6964 histP = (histP + 1) % HISTORY_SIZE;
\r
6965 return history[histP];
\r
6969 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6973 hmenu = LoadMenu(hInst, "TextMenu");
\r
6974 h = GetSubMenu(hmenu, 0);
\r
6976 if (strcmp(e->item, "-") == 0) {
\r
6977 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6978 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6979 int flags = MF_STRING, j = 0;
\r
6980 if (e->item[0] == '|') {
\r
6981 flags |= MF_MENUBARBREAK;
\r
6984 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6985 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6993 WNDPROC consoleTextWindowProc;
\r
6996 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6998 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6999 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7003 SetWindowText(hInput, command);
\r
7005 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7007 sel.cpMin = 999999;
\r
7008 sel.cpMax = 999999;
\r
7009 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7014 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7015 if (sel.cpMin == sel.cpMax) {
\r
7016 /* Expand to surrounding word */
\r
7019 tr.chrg.cpMax = sel.cpMin;
\r
7020 tr.chrg.cpMin = --sel.cpMin;
\r
7021 if (sel.cpMin < 0) break;
\r
7022 tr.lpstrText = name;
\r
7023 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7024 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7028 tr.chrg.cpMin = sel.cpMax;
\r
7029 tr.chrg.cpMax = ++sel.cpMax;
\r
7030 tr.lpstrText = name;
\r
7031 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7032 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7035 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7036 MessageBeep(MB_ICONEXCLAMATION);
\r
7040 tr.lpstrText = name;
\r
7041 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7043 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7044 MessageBeep(MB_ICONEXCLAMATION);
\r
7047 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7050 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7051 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7052 SetWindowText(hInput, buf);
\r
7053 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7055 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7056 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7057 SetWindowText(hInput, buf);
\r
7058 sel.cpMin = 999999;
\r
7059 sel.cpMax = 999999;
\r
7060 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7066 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7071 switch (message) {
\r
7073 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7074 if(wParam=='R') return 0;
\r
7077 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7080 sel.cpMin = 999999;
\r
7081 sel.cpMax = 999999;
\r
7082 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7083 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7088 if(wParam != '\022') {
\r
7089 if (wParam == '\t') {
\r
7090 if (GetKeyState(VK_SHIFT) < 0) {
\r
7092 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7093 if (buttonDesc[0].hwnd) {
\r
7094 SetFocus(buttonDesc[0].hwnd);
\r
7096 SetFocus(hwndMain);
\r
7100 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7103 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7104 JAWS_DELETE( SetFocus(hInput); )
\r
7105 SendMessage(hInput, message, wParam, lParam);
\r
7108 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7110 case WM_RBUTTONDOWN:
\r
7111 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7112 /* Move selection here if it was empty */
\r
7114 pt.x = LOWORD(lParam);
\r
7115 pt.y = HIWORD(lParam);
\r
7116 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7117 if (sel.cpMin == sel.cpMax) {
\r
7118 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7119 sel.cpMax = sel.cpMin;
\r
7120 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7122 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7123 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7125 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7126 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7127 if (sel.cpMin == sel.cpMax) {
\r
7128 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7129 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7131 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7132 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7134 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7135 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7136 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7137 MenuPopup(hwnd, pt, hmenu, -1);
\r
7141 case WM_RBUTTONUP:
\r
7142 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7143 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7144 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7148 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7150 return SendMessage(hInput, message, wParam, lParam);
\r
7151 case WM_MBUTTONDOWN:
\r
7152 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7154 switch (LOWORD(wParam)) {
\r
7155 case IDM_QuickPaste:
\r
7157 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7158 if (sel.cpMin == sel.cpMax) {
\r
7159 MessageBeep(MB_ICONEXCLAMATION);
\r
7162 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7163 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7164 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7169 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7172 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7175 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7179 int i = LOWORD(wParam) - IDM_CommandX;
\r
7180 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7181 icsTextMenuEntry[i].command != NULL) {
\r
7182 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7183 icsTextMenuEntry[i].getname,
\r
7184 icsTextMenuEntry[i].immediate);
\r
7192 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7195 WNDPROC consoleInputWindowProc;
\r
7198 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7200 char buf[MSG_SIZ];
\r
7202 static BOOL sendNextChar = FALSE;
\r
7203 static BOOL quoteNextChar = FALSE;
\r
7204 InputSource *is = consoleInputSource;
\r
7208 switch (message) {
\r
7210 if (!appData.localLineEditing || sendNextChar) {
\r
7211 is->buf[0] = (CHAR) wParam;
\r
7213 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7214 sendNextChar = FALSE;
\r
7217 if (quoteNextChar) {
\r
7218 buf[0] = (char) wParam;
\r
7219 buf[1] = NULLCHAR;
\r
7220 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7221 quoteNextChar = FALSE;
\r
7225 case '\r': /* Enter key */
\r
7226 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7227 if (consoleEcho) SaveInHistory(is->buf);
\r
7228 is->buf[is->count++] = '\n';
\r
7229 is->buf[is->count] = NULLCHAR;
\r
7230 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7231 if (consoleEcho) {
\r
7232 ConsoleOutput(is->buf, is->count, TRUE);
\r
7233 } else if (appData.localLineEditing) {
\r
7234 ConsoleOutput("\n", 1, TRUE);
\r
7237 case '\033': /* Escape key */
\r
7238 SetWindowText(hwnd, "");
\r
7239 cf.cbSize = sizeof(CHARFORMAT);
\r
7240 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7241 if (consoleEcho) {
\r
7242 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7244 cf.crTextColor = COLOR_ECHOOFF;
\r
7246 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7247 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7249 case '\t': /* Tab key */
\r
7250 if (GetKeyState(VK_SHIFT) < 0) {
\r
7252 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7255 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7256 if (buttonDesc[0].hwnd) {
\r
7257 SetFocus(buttonDesc[0].hwnd);
\r
7259 SetFocus(hwndMain);
\r
7263 case '\023': /* Ctrl+S */
\r
7264 sendNextChar = TRUE;
\r
7266 case '\021': /* Ctrl+Q */
\r
7267 quoteNextChar = TRUE;
\r
7277 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7278 p = PrevInHistory(buf);
\r
7280 SetWindowText(hwnd, p);
\r
7281 sel.cpMin = 999999;
\r
7282 sel.cpMax = 999999;
\r
7283 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7288 p = NextInHistory();
\r
7290 SetWindowText(hwnd, p);
\r
7291 sel.cpMin = 999999;
\r
7292 sel.cpMax = 999999;
\r
7293 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7299 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7303 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7307 case WM_MBUTTONDOWN:
\r
7308 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7309 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7311 case WM_RBUTTONUP:
\r
7312 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7313 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7314 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7318 hmenu = LoadMenu(hInst, "InputMenu");
\r
7319 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7320 if (sel.cpMin == sel.cpMax) {
\r
7321 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7322 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7324 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7325 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7327 pt.x = LOWORD(lParam);
\r
7328 pt.y = HIWORD(lParam);
\r
7329 MenuPopup(hwnd, pt, hmenu, -1);
\r
7333 switch (LOWORD(wParam)) {
\r
7335 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7337 case IDM_SelectAll:
\r
7339 sel.cpMax = -1; /*999999?*/
\r
7340 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7343 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7346 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7349 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7354 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7357 #define CO_MAX 100000
\r
7358 #define CO_TRIM 1000
\r
7361 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7363 static SnapData sd;
\r
7364 HWND hText, hInput;
\r
7366 static int sizeX, sizeY;
\r
7367 int newSizeX, newSizeY;
\r
7371 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7372 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7374 switch (message) {
\r
7376 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7378 ENLINK *pLink = (ENLINK*)lParam;
\r
7379 if (pLink->msg == WM_LBUTTONUP)
\r
7383 tr.chrg = pLink->chrg;
\r
7384 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7385 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7386 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7387 free(tr.lpstrText);
\r
7391 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7392 hwndConsole = hDlg;
\r
7394 consoleTextWindowProc = (WNDPROC)
\r
7395 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7396 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7397 consoleInputWindowProc = (WNDPROC)
\r
7398 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7399 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7400 Colorize(ColorNormal, TRUE);
\r
7401 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7402 ChangedConsoleFont();
\r
7403 GetClientRect(hDlg, &rect);
\r
7404 sizeX = rect.right;
\r
7405 sizeY = rect.bottom;
\r
7406 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7407 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7408 WINDOWPLACEMENT wp;
\r
7409 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7410 wp.length = sizeof(WINDOWPLACEMENT);
\r
7412 wp.showCmd = SW_SHOW;
\r
7413 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7414 wp.rcNormalPosition.left = wpConsole.x;
\r
7415 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7416 wp.rcNormalPosition.top = wpConsole.y;
\r
7417 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7418 SetWindowPlacement(hDlg, &wp);
\r
7421 // [HGM] Chessknight's change 2004-07-13
\r
7422 else { /* Determine Defaults */
\r
7423 WINDOWPLACEMENT wp;
\r
7424 wpConsole.x = wpMain.width + 1;
\r
7425 wpConsole.y = wpMain.y;
\r
7426 wpConsole.width = screenWidth - wpMain.width;
\r
7427 wpConsole.height = wpMain.height;
\r
7428 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7429 wp.length = sizeof(WINDOWPLACEMENT);
\r
7431 wp.showCmd = SW_SHOW;
\r
7432 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7433 wp.rcNormalPosition.left = wpConsole.x;
\r
7434 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7435 wp.rcNormalPosition.top = wpConsole.y;
\r
7436 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7437 SetWindowPlacement(hDlg, &wp);
\r
7440 // Allow hText to highlight URLs and send notifications on them
\r
7441 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7442 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7443 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7444 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7458 if (IsIconic(hDlg)) break;
\r
7459 newSizeX = LOWORD(lParam);
\r
7460 newSizeY = HIWORD(lParam);
\r
7461 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7462 RECT rectText, rectInput;
\r
7464 int newTextHeight, newTextWidth;
\r
7465 GetWindowRect(hText, &rectText);
\r
7466 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7467 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7468 if (newTextHeight < 0) {
\r
7469 newSizeY += -newTextHeight;
\r
7470 newTextHeight = 0;
\r
7472 SetWindowPos(hText, NULL, 0, 0,
\r
7473 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7474 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7475 pt.x = rectInput.left;
\r
7476 pt.y = rectInput.top + newSizeY - sizeY;
\r
7477 ScreenToClient(hDlg, &pt);
\r
7478 SetWindowPos(hInput, NULL,
\r
7479 pt.x, pt.y, /* needs client coords */
\r
7480 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7481 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7487 case WM_GETMINMAXINFO:
\r
7488 /* Prevent resizing window too small */
\r
7489 mmi = (MINMAXINFO *) lParam;
\r
7490 mmi->ptMinTrackSize.x = 100;
\r
7491 mmi->ptMinTrackSize.y = 100;
\r
7494 /* [AS] Snapping */
\r
7495 case WM_ENTERSIZEMOVE:
\r
7496 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7499 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7502 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7504 case WM_EXITSIZEMOVE:
\r
7505 UpdateICSWidth(hText);
\r
7506 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7509 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7517 if (hwndConsole) return;
\r
7518 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7519 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7524 ConsoleOutput(char* data, int length, int forceVisible)
\r
7529 char buf[CO_MAX+1];
\r
7532 static int delayLF = 0;
\r
7533 CHARRANGE savesel, sel;
\r
7535 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7543 while (length--) {
\r
7551 } else if (*p == '\007') {
\r
7552 MyPlaySound(&sounds[(int)SoundBell]);
\r
7559 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7560 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7561 /* Save current selection */
\r
7562 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7563 exlen = GetWindowTextLength(hText);
\r
7564 /* Find out whether current end of text is visible */
\r
7565 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7566 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7567 /* Trim existing text if it's too long */
\r
7568 if (exlen + (q - buf) > CO_MAX) {
\r
7569 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7572 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7573 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7575 savesel.cpMin -= trim;
\r
7576 savesel.cpMax -= trim;
\r
7577 if (exlen < 0) exlen = 0;
\r
7578 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7579 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7581 /* Append the new text */
\r
7582 sel.cpMin = exlen;
\r
7583 sel.cpMax = exlen;
\r
7584 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7585 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7586 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7587 if (forceVisible || exlen == 0 ||
\r
7588 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7589 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7590 /* Scroll to make new end of text visible if old end of text
\r
7591 was visible or new text is an echo of user typein */
\r
7592 sel.cpMin = 9999999;
\r
7593 sel.cpMax = 9999999;
\r
7594 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7595 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7596 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7597 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7599 if (savesel.cpMax == exlen || forceVisible) {
\r
7600 /* Move insert point to new end of text if it was at the old
\r
7601 end of text or if the new text is an echo of user typein */
\r
7602 sel.cpMin = 9999999;
\r
7603 sel.cpMax = 9999999;
\r
7604 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7606 /* Restore previous selection */
\r
7607 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7609 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7616 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7620 COLORREF oldFg, oldBg;
\r
7624 if(copyNumber > 1)
\r
7625 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7627 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7628 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7629 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7632 rect.right = x + squareSize;
\r
7634 rect.bottom = y + squareSize;
\r
7637 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7638 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7639 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7640 &rect, str, strlen(str), NULL);
\r
7642 (void) SetTextColor(hdc, oldFg);
\r
7643 (void) SetBkColor(hdc, oldBg);
\r
7644 (void) SelectObject(hdc, oldFont);
\r
7648 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7649 RECT *rect, char *color, char *flagFell)
\r
7653 COLORREF oldFg, oldBg;
\r
7656 if (twoBoards && partnerUp) return;
\r
7657 if (appData.clockMode) {
\r
7658 if (tinyLayout == 2)
\r
7659 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7661 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7668 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7669 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7671 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7672 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7674 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7678 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7679 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7680 rect, str, strlen(str), NULL);
\r
7681 if(logoHeight > 0 && appData.clockMode) {
\r
7683 str += strlen(color)+2;
\r
7684 r.top = rect->top + logoHeight/2;
\r
7685 r.left = rect->left;
\r
7686 r.right = rect->right;
\r
7687 r.bottom = rect->bottom;
\r
7688 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7689 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7690 &r, str, strlen(str), NULL);
\r
7692 (void) SetTextColor(hdc, oldFg);
\r
7693 (void) SetBkColor(hdc, oldBg);
\r
7694 (void) SelectObject(hdc, oldFont);
\r
7699 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7705 if( count <= 0 ) {
\r
7706 if (appData.debugMode) {
\r
7707 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7710 return ERROR_INVALID_USER_BUFFER;
\r
7713 ResetEvent(ovl->hEvent);
\r
7714 ovl->Offset = ovl->OffsetHigh = 0;
\r
7715 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7719 err = GetLastError();
\r
7720 if (err == ERROR_IO_PENDING) {
\r
7721 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7725 err = GetLastError();
\r
7732 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7737 ResetEvent(ovl->hEvent);
\r
7738 ovl->Offset = ovl->OffsetHigh = 0;
\r
7739 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7743 err = GetLastError();
\r
7744 if (err == ERROR_IO_PENDING) {
\r
7745 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7749 err = GetLastError();
\r
7756 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7757 void CheckForInputBufferFull( InputSource * is )
\r
7759 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7760 /* Look for end of line */
\r
7761 char * p = is->buf;
\r
7763 while( p < is->next && *p != '\n' ) {
\r
7767 if( p >= is->next ) {
\r
7768 if (appData.debugMode) {
\r
7769 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7772 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7773 is->count = (DWORD) -1;
\r
7774 is->next = is->buf;
\r
7780 InputThread(LPVOID arg)
\r
7785 is = (InputSource *) arg;
\r
7786 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7787 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7788 while (is->hThread != NULL) {
\r
7789 is->error = DoReadFile(is->hFile, is->next,
\r
7790 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7791 &is->count, &ovl);
\r
7792 if (is->error == NO_ERROR) {
\r
7793 is->next += is->count;
\r
7795 if (is->error == ERROR_BROKEN_PIPE) {
\r
7796 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7799 is->count = (DWORD) -1;
\r
7800 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7805 CheckForInputBufferFull( is );
\r
7807 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7809 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7811 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7814 CloseHandle(ovl.hEvent);
\r
7815 CloseHandle(is->hFile);
\r
7817 if (appData.debugMode) {
\r
7818 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7825 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7827 NonOvlInputThread(LPVOID arg)
\r
7834 is = (InputSource *) arg;
\r
7835 while (is->hThread != NULL) {
\r
7836 is->error = ReadFile(is->hFile, is->next,
\r
7837 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7838 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7839 if (is->error == NO_ERROR) {
\r
7840 /* Change CRLF to LF */
\r
7841 if (is->next > is->buf) {
\r
7843 i = is->count + 1;
\r
7851 if (prev == '\r' && *p == '\n') {
\r
7863 if (is->error == ERROR_BROKEN_PIPE) {
\r
7864 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7867 is->count = (DWORD) -1;
\r
7871 CheckForInputBufferFull( is );
\r
7873 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7875 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7877 if (is->count < 0) break; /* Quit on error */
\r
7879 CloseHandle(is->hFile);
\r
7884 SocketInputThread(LPVOID arg)
\r
7888 is = (InputSource *) arg;
\r
7889 while (is->hThread != NULL) {
\r
7890 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7891 if ((int)is->count == SOCKET_ERROR) {
\r
7892 is->count = (DWORD) -1;
\r
7893 is->error = WSAGetLastError();
\r
7895 is->error = NO_ERROR;
\r
7896 is->next += is->count;
\r
7897 if (is->count == 0 && is->second == is) {
\r
7898 /* End of file on stderr; quit with no message */
\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 EOF or error */
\r
7912 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7916 is = (InputSource *) lParam;
\r
7917 if (is->lineByLine) {
\r
7918 /* Feed in lines one by one */
\r
7919 char *p = is->buf;
\r
7921 while (q < is->next) {
\r
7922 if (*q++ == '\n') {
\r
7923 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7928 /* Move any partial line to the start of the buffer */
\r
7930 while (p < is->next) {
\r
7935 if (is->error != NO_ERROR || is->count == 0) {
\r
7936 /* Notify backend of the error. Note: If there was a partial
\r
7937 line at the end, it is not flushed through. */
\r
7938 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7941 /* Feed in the whole chunk of input at once */
\r
7942 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7943 is->next = is->buf;
\r
7947 /*---------------------------------------------------------------------------*\
\r
7949 * Menu enables. Used when setting various modes.
\r
7951 \*---------------------------------------------------------------------------*/
\r
7959 GreyRevert(Boolean grey)
\r
7960 { // [HGM] vari: for retracting variations in local mode
\r
7961 HMENU hmenu = GetMenu(hwndMain);
\r
7962 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7963 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7967 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7969 while (enab->item > 0) {
\r
7970 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7975 Enables gnuEnables[] = {
\r
7976 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7980 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7981 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7982 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7983 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7984 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7985 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7986 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7987 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7988 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7990 // Needed to switch from ncp to GNU mode on Engine Load
\r
7991 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7992 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7994 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7995 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7996 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7997 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
8000 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
8001 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8002 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8003 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8004 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8008 Enables icsEnables[] = {
\r
8009 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8017 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8020 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8024 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8025 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8026 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8027 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8028 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8033 Enables zippyEnables[] = {
\r
8034 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8037 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8042 Enables ncpEnables[] = {
\r
8043 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8053 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8055 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8056 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8068 Enables trainingOnEnables[] = {
\r
8069 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8075 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8076 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8077 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8081 Enables trainingOffEnables[] = {
\r
8082 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8083 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8084 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8085 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8086 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8087 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8088 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8089 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8090 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8094 /* These modify either ncpEnables or gnuEnables */
\r
8095 Enables cmailEnables[] = {
\r
8096 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8097 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8098 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8099 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8100 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8101 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8102 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8106 Enables machineThinkingEnables[] = {
\r
8107 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8114 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8115 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8116 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8117 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8118 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8119 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8120 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8121 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8122 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8126 Enables userThinkingEnables[] = {
\r
8127 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8133 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8134 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8135 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8136 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8137 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8138 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8139 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8140 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8141 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8142 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8146 /*---------------------------------------------------------------------------*\
\r
8148 * Front-end interface functions exported by XBoard.
\r
8149 * Functions appear in same order as prototypes in frontend.h.
\r
8151 \*---------------------------------------------------------------------------*/
\r
8153 CheckMark(UINT item, int state)
\r
8155 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8161 static UINT prevChecked = 0;
\r
8162 static int prevPausing = 0;
\r
8165 if (pausing != prevPausing) {
\r
8166 prevPausing = pausing;
\r
8167 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8168 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8169 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8172 switch (gameMode) {
\r
8173 case BeginningOfGame:
\r
8174 if (appData.icsActive)
\r
8175 nowChecked = IDM_IcsClient;
\r
8176 else if (appData.noChessProgram)
\r
8177 nowChecked = IDM_EditGame;
\r
8179 nowChecked = IDM_MachineBlack;
\r
8181 case MachinePlaysBlack:
\r
8182 nowChecked = IDM_MachineBlack;
\r
8184 case MachinePlaysWhite:
\r
8185 nowChecked = IDM_MachineWhite;
\r
8187 case TwoMachinesPlay:
\r
8188 nowChecked = IDM_TwoMachines;
\r
8191 nowChecked = IDM_AnalysisMode;
\r
8194 nowChecked = IDM_AnalyzeFile;
\r
8197 nowChecked = IDM_EditGame;
\r
8199 case PlayFromGameFile:
\r
8200 nowChecked = IDM_LoadGame;
\r
8202 case EditPosition:
\r
8203 nowChecked = IDM_EditPosition;
\r
8206 nowChecked = IDM_Training;
\r
8208 case IcsPlayingWhite:
\r
8209 case IcsPlayingBlack:
\r
8210 case IcsObserving:
\r
8212 nowChecked = IDM_IcsClient;
\r
8219 if(prevChecked == IDM_TwoMachine) // [HGM] 'Machine Match' might have gotten disabled when stopping match
\r
8220 EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED)
\r
8221 CheckMark(prevChecked, MF_UNCHECKED);
\r
8222 CheckMark(nowChecked, MF_CHECKED);
\r
8223 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8225 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8226 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8227 MF_BYCOMMAND|MF_ENABLED);
\r
8229 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8230 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8233 prevChecked = nowChecked;
\r
8235 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8236 if (appData.icsActive) {
\r
8237 if (appData.icsEngineAnalyze) {
\r
8238 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8240 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8243 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8249 HMENU hmenu = GetMenu(hwndMain);
\r
8250 SetMenuEnables(hmenu, icsEnables);
\r
8251 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8252 MF_BYCOMMAND|MF_ENABLED);
\r
8254 if (appData.zippyPlay) {
\r
8255 SetMenuEnables(hmenu, zippyEnables);
\r
8256 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8257 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8258 MF_BYCOMMAND|MF_ENABLED);
\r
8266 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8272 HMENU hmenu = GetMenu(hwndMain);
\r
8273 SetMenuEnables(hmenu, ncpEnables);
\r
8274 DrawMenuBar(hwndMain);
\r
8280 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8284 SetTrainingModeOn()
\r
8287 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8288 for (i = 0; i < N_BUTTONS; i++) {
\r
8289 if (buttonDesc[i].hwnd != NULL)
\r
8290 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8295 VOID SetTrainingModeOff()
\r
8298 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8299 for (i = 0; i < N_BUTTONS; i++) {
\r
8300 if (buttonDesc[i].hwnd != NULL)
\r
8301 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8307 SetUserThinkingEnables()
\r
8309 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8313 SetMachineThinkingEnables()
\r
8315 HMENU hMenu = GetMenu(hwndMain);
\r
8316 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8318 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8320 if (gameMode == MachinePlaysBlack) {
\r
8321 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8322 } else if (gameMode == MachinePlaysWhite) {
\r
8323 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8324 } else if (gameMode == TwoMachinesPlay) {
\r
8325 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8331 DisplayTitle(char *str)
\r
8333 char title[MSG_SIZ], *host;
\r
8334 if (str[0] != NULLCHAR) {
\r
8335 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8336 } else if (appData.icsActive) {
\r
8337 if (appData.icsCommPort[0] != NULLCHAR)
\r
8340 host = appData.icsHost;
\r
8341 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8342 } else if (appData.noChessProgram) {
\r
8343 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8345 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8346 strcat(title, ": ");
\r
8347 strcat(title, first.tidy);
\r
8349 SetWindowText(hwndMain, title);
\r
8354 DisplayMessage(char *str1, char *str2)
\r
8358 int remain = MESSAGE_TEXT_MAX - 1;
\r
8361 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8362 messageText[0] = NULLCHAR;
\r
8364 len = strlen(str1);
\r
8365 if (len > remain) len = remain;
\r
8366 strncpy(messageText, str1, len);
\r
8367 messageText[len] = NULLCHAR;
\r
8370 if (*str2 && remain >= 2) {
\r
8372 strcat(messageText, " ");
\r
8375 len = strlen(str2);
\r
8376 if (len > remain) len = remain;
\r
8377 strncat(messageText, str2, len);
\r
8379 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8380 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8382 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8386 hdc = GetDC(hwndMain);
\r
8387 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8388 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8389 &messageRect, messageText, strlen(messageText), NULL);
\r
8390 (void) SelectObject(hdc, oldFont);
\r
8391 (void) ReleaseDC(hwndMain, hdc);
\r
8395 DisplayError(char *str, int error)
\r
8397 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8401 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8403 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8404 NULL, error, LANG_NEUTRAL,
\r
8405 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8407 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8409 ErrorMap *em = errmap;
\r
8410 while (em->err != 0 && em->err != error) em++;
\r
8411 if (em->err != 0) {
\r
8412 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8414 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8419 ErrorPopUp(_("Error"), buf);
\r
8424 DisplayMoveError(char *str)
\r
8426 fromX = fromY = -1;
\r
8427 ClearHighlights();
\r
8428 DrawPosition(FALSE, NULL);
\r
8429 if (appData.popupMoveErrors) {
\r
8430 ErrorPopUp(_("Error"), str);
\r
8432 DisplayMessage(str, "");
\r
8433 moveErrorMessageUp = TRUE;
\r
8438 DisplayFatalError(char *str, int error, int exitStatus)
\r
8440 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8442 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8445 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8446 NULL, error, LANG_NEUTRAL,
\r
8447 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8449 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8451 ErrorMap *em = errmap;
\r
8452 while (em->err != 0 && em->err != error) em++;
\r
8453 if (em->err != 0) {
\r
8454 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8456 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8461 if (appData.debugMode) {
\r
8462 fprintf(debugFP, "%s: %s\n", label, str);
\r
8464 if (appData.popupExitMessage) {
\r
8465 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8466 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8468 ExitEvent(exitStatus);
\r
8473 DisplayInformation(char *str)
\r
8475 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8480 DisplayNote(char *str)
\r
8482 ErrorPopUp(_("Note"), str);
\r
8487 char *title, *question, *replyPrefix;
\r
8492 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8494 static QuestionParams *qp;
\r
8495 char reply[MSG_SIZ];
\r
8498 switch (message) {
\r
8499 case WM_INITDIALOG:
\r
8500 qp = (QuestionParams *) lParam;
\r
8501 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8502 Translate(hDlg, DLG_Question);
\r
8503 SetWindowText(hDlg, qp->title);
\r
8504 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8505 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8509 switch (LOWORD(wParam)) {
\r
8511 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8512 if (*reply) strcat(reply, " ");
\r
8513 len = strlen(reply);
\r
8514 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8515 strcat(reply, "\n");
\r
8516 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8517 EndDialog(hDlg, TRUE);
\r
8518 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8521 EndDialog(hDlg, FALSE);
\r
8532 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8534 QuestionParams qp;
\r
8538 qp.question = question;
\r
8539 qp.replyPrefix = replyPrefix;
\r
8541 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8542 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8543 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8544 FreeProcInstance(lpProc);
\r
8547 /* [AS] Pick FRC position */
\r
8548 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8550 static int * lpIndexFRC;
\r
8556 case WM_INITDIALOG:
\r
8557 lpIndexFRC = (int *) lParam;
\r
8559 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8560 Translate(hDlg, DLG_NewGameFRC);
\r
8562 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8563 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8564 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8565 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8570 switch( LOWORD(wParam) ) {
\r
8572 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8573 EndDialog( hDlg, 0 );
\r
8574 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8577 EndDialog( hDlg, 1 );
\r
8579 case IDC_NFG_Edit:
\r
8580 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8581 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8583 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8586 case IDC_NFG_Random:
\r
8587 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8588 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8601 int index = appData.defaultFrcPosition;
\r
8602 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8604 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8606 if( result == 0 ) {
\r
8607 appData.defaultFrcPosition = index;
\r
8613 /* [AS] Game list options. Refactored by HGM */
\r
8615 HWND gameListOptionsDialog;
\r
8617 // low-level front-end: clear text edit / list widget
\r
8622 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8625 // low-level front-end: clear text edit / list widget
\r
8627 GLT_DeSelectList()
\r
8629 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8632 // low-level front-end: append line to text edit / list widget
\r
8634 GLT_AddToList( char *name )
\r
8637 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8641 // low-level front-end: get line from text edit / list widget
\r
8643 GLT_GetFromList( int index, char *name )
\r
8646 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8652 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8654 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8655 int idx2 = idx1 + delta;
\r
8656 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8658 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8661 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8662 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8663 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8664 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8668 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8672 case WM_INITDIALOG:
\r
8673 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8675 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8676 Translate(hDlg, DLG_GameListOptions);
\r
8678 /* Initialize list */
\r
8679 GLT_TagsToList( lpUserGLT );
\r
8681 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8686 switch( LOWORD(wParam) ) {
\r
8689 EndDialog( hDlg, 0 );
\r
8692 EndDialog( hDlg, 1 );
\r
8695 case IDC_GLT_Default:
\r
8696 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8699 case IDC_GLT_Restore:
\r
8700 GLT_TagsToList( appData.gameListTags );
\r
8704 GLT_MoveSelection( hDlg, -1 );
\r
8707 case IDC_GLT_Down:
\r
8708 GLT_MoveSelection( hDlg, +1 );
\r
8718 int GameListOptions()
\r
8721 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8723 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8725 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8727 if( result == 0 ) {
\r
8728 char *oldTags = appData.gameListTags;
\r
8729 /* [AS] Memory leak here! */
\r
8730 appData.gameListTags = strdup( lpUserGLT );
\r
8731 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8732 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8739 DisplayIcsInteractionTitle(char *str)
\r
8741 char consoleTitle[MSG_SIZ];
\r
8743 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8744 SetWindowText(hwndConsole, consoleTitle);
\r
8746 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8747 char buf[MSG_SIZ], *p = buf, *q;
\r
8748 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8750 q = strchr(p, ';');
\r
8752 if(*p) ChatPopUp(p);
\r
8756 SetActiveWindow(hwndMain);
\r
8760 DrawPosition(int fullRedraw, Board board)
\r
8762 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8765 void NotifyFrontendLogin()
\r
8768 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8774 fromX = fromY = -1;
\r
8775 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8776 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8777 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8778 dragInfo.lastpos = dragInfo.pos;
\r
8779 dragInfo.start.x = dragInfo.start.y = -1;
\r
8780 dragInfo.from = dragInfo.start;
\r
8782 DrawPosition(TRUE, NULL);
\r
8789 CommentPopUp(char *title, char *str)
\r
8791 HWND hwnd = GetActiveWindow();
\r
8792 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8794 SetActiveWindow(hwnd);
\r
8798 CommentPopDown(void)
\r
8800 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8801 if (commentDialog) {
\r
8802 ShowWindow(commentDialog, SW_HIDE);
\r
8804 commentUp = FALSE;
\r
8808 EditCommentPopUp(int index, char *title, char *str)
\r
8810 EitherCommentPopUp(index, title, str, TRUE);
\r
8817 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8824 MyPlaySound(&sounds[(int)SoundMove]);
\r
8827 VOID PlayIcsWinSound()
\r
8829 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8832 VOID PlayIcsLossSound()
\r
8834 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8837 VOID PlayIcsDrawSound()
\r
8839 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8842 VOID PlayIcsUnfinishedSound()
\r
8844 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8850 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8856 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8864 consoleEcho = TRUE;
\r
8865 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8866 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8867 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8876 consoleEcho = FALSE;
\r
8877 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8878 /* This works OK: set text and background both to the same color */
\r
8880 cf.crTextColor = COLOR_ECHOOFF;
\r
8881 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8882 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8885 /* No Raw()...? */
\r
8887 void Colorize(ColorClass cc, int continuation)
\r
8889 currentColorClass = cc;
\r
8890 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8891 consoleCF.crTextColor = textAttribs[cc].color;
\r
8892 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8893 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8899 static char buf[MSG_SIZ];
\r
8900 DWORD bufsiz = MSG_SIZ;
\r
8902 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8903 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8905 if (!GetUserName(buf, &bufsiz)) {
\r
8906 /*DisplayError("Error getting user name", GetLastError());*/
\r
8907 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8915 static char buf[MSG_SIZ];
\r
8916 DWORD bufsiz = MSG_SIZ;
\r
8918 if (!GetComputerName(buf, &bufsiz)) {
\r
8919 /*DisplayError("Error getting host name", GetLastError());*/
\r
8920 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8927 ClockTimerRunning()
\r
8929 return clockTimerEvent != 0;
\r
8935 if (clockTimerEvent == 0) return FALSE;
\r
8936 KillTimer(hwndMain, clockTimerEvent);
\r
8937 clockTimerEvent = 0;
\r
8942 StartClockTimer(long millisec)
\r
8944 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8945 (UINT) millisec, NULL);
\r
8949 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8952 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8954 if(appData.noGUI) return;
\r
8955 hdc = GetDC(hwndMain);
\r
8956 if (!IsIconic(hwndMain)) {
\r
8957 DisplayAClock(hdc, timeRemaining, highlight,
\r
8958 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8960 if (highlight && iconCurrent == iconBlack) {
\r
8961 iconCurrent = iconWhite;
\r
8962 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8963 if (IsIconic(hwndMain)) {
\r
8964 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8967 (void) ReleaseDC(hwndMain, hdc);
\r
8969 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8973 DisplayBlackClock(long timeRemaining, int highlight)
\r
8976 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8979 if(appData.noGUI) return;
\r
8980 hdc = GetDC(hwndMain);
\r
8981 if (!IsIconic(hwndMain)) {
\r
8982 DisplayAClock(hdc, timeRemaining, highlight,
\r
8983 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8985 if (highlight && iconCurrent == iconWhite) {
\r
8986 iconCurrent = iconBlack;
\r
8987 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8988 if (IsIconic(hwndMain)) {
\r
8989 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8992 (void) ReleaseDC(hwndMain, hdc);
\r
8994 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8999 LoadGameTimerRunning()
\r
9001 return loadGameTimerEvent != 0;
\r
9005 StopLoadGameTimer()
\r
9007 if (loadGameTimerEvent == 0) return FALSE;
\r
9008 KillTimer(hwndMain, loadGameTimerEvent);
\r
9009 loadGameTimerEvent = 0;
\r
9014 StartLoadGameTimer(long millisec)
\r
9016 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9017 (UINT) millisec, NULL);
\r
9025 char fileTitle[MSG_SIZ];
\r
9027 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9028 f = OpenFileDialog(hwndMain, "a", defName,
\r
9029 appData.oldSaveStyle ? "gam" : "pgn",
\r
9031 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9033 SaveGame(f, 0, "");
\r
9040 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9042 if (delayedTimerEvent != 0) {
\r
9043 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9044 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9046 KillTimer(hwndMain, delayedTimerEvent);
\r
9047 delayedTimerEvent = 0;
\r
9048 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9049 delayedTimerCallback();
\r
9051 delayedTimerCallback = cb;
\r
9052 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9053 (UINT) millisec, NULL);
\r
9056 DelayedEventCallback
\r
9059 if (delayedTimerEvent) {
\r
9060 return delayedTimerCallback;
\r
9067 CancelDelayedEvent()
\r
9069 if (delayedTimerEvent) {
\r
9070 KillTimer(hwndMain, delayedTimerEvent);
\r
9071 delayedTimerEvent = 0;
\r
9075 DWORD GetWin32Priority(int nice)
\r
9076 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9078 REALTIME_PRIORITY_CLASS 0x00000100
\r
9079 HIGH_PRIORITY_CLASS 0x00000080
\r
9080 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9081 NORMAL_PRIORITY_CLASS 0x00000020
\r
9082 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9083 IDLE_PRIORITY_CLASS 0x00000040
\r
9085 if (nice < -15) return 0x00000080;
\r
9086 if (nice < 0) return 0x00008000;
\r
9087 if (nice == 0) return 0x00000020;
\r
9088 if (nice < 15) return 0x00004000;
\r
9089 return 0x00000040;
\r
9092 void RunCommand(char *cmdLine)
\r
9094 /* Now create the child process. */
\r
9095 STARTUPINFO siStartInfo;
\r
9096 PROCESS_INFORMATION piProcInfo;
\r
9098 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9099 siStartInfo.lpReserved = NULL;
\r
9100 siStartInfo.lpDesktop = NULL;
\r
9101 siStartInfo.lpTitle = NULL;
\r
9102 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9103 siStartInfo.cbReserved2 = 0;
\r
9104 siStartInfo.lpReserved2 = NULL;
\r
9105 siStartInfo.hStdInput = NULL;
\r
9106 siStartInfo.hStdOutput = NULL;
\r
9107 siStartInfo.hStdError = NULL;
\r
9109 CreateProcess(NULL,
\r
9110 cmdLine, /* command line */
\r
9111 NULL, /* process security attributes */
\r
9112 NULL, /* primary thread security attrs */
\r
9113 TRUE, /* handles are inherited */
\r
9114 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9115 NULL, /* use parent's environment */
\r
9117 &siStartInfo, /* STARTUPINFO pointer */
\r
9118 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9120 CloseHandle(piProcInfo.hThread);
\r
9123 /* Start a child process running the given program.
\r
9124 The process's standard output can be read from "from", and its
\r
9125 standard input can be written to "to".
\r
9126 Exit with fatal error if anything goes wrong.
\r
9127 Returns an opaque pointer that can be used to destroy the process
\r
9131 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9133 #define BUFSIZE 4096
\r
9135 HANDLE hChildStdinRd, hChildStdinWr,
\r
9136 hChildStdoutRd, hChildStdoutWr;
\r
9137 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9138 SECURITY_ATTRIBUTES saAttr;
\r
9140 PROCESS_INFORMATION piProcInfo;
\r
9141 STARTUPINFO siStartInfo;
\r
9143 char buf[MSG_SIZ];
\r
9146 if (appData.debugMode) {
\r
9147 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9152 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9153 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9154 saAttr.bInheritHandle = TRUE;
\r
9155 saAttr.lpSecurityDescriptor = NULL;
\r
9158 * The steps for redirecting child's STDOUT:
\r
9159 * 1. Create anonymous pipe to be STDOUT for child.
\r
9160 * 2. Create a noninheritable duplicate of read handle,
\r
9161 * and close the inheritable read handle.
\r
9164 /* Create a pipe for the child's STDOUT. */
\r
9165 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9166 return GetLastError();
\r
9169 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9170 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9171 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9172 FALSE, /* not inherited */
\r
9173 DUPLICATE_SAME_ACCESS);
\r
9175 return GetLastError();
\r
9177 CloseHandle(hChildStdoutRd);
\r
9180 * The steps for redirecting child's STDIN:
\r
9181 * 1. Create anonymous pipe to be STDIN for child.
\r
9182 * 2. Create a noninheritable duplicate of write handle,
\r
9183 * and close the inheritable write handle.
\r
9186 /* Create a pipe for the child's STDIN. */
\r
9187 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9188 return GetLastError();
\r
9191 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9192 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9193 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9194 FALSE, /* not inherited */
\r
9195 DUPLICATE_SAME_ACCESS);
\r
9197 return GetLastError();
\r
9199 CloseHandle(hChildStdinWr);
\r
9201 /* Arrange to (1) look in dir for the child .exe file, and
\r
9202 * (2) have dir be the child's working directory. Interpret
\r
9203 * dir relative to the directory WinBoard loaded from. */
\r
9204 GetCurrentDirectory(MSG_SIZ, buf);
\r
9205 SetCurrentDirectory(installDir);
\r
9206 SetCurrentDirectory(dir);
\r
9208 /* Now create the child process. */
\r
9210 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9211 siStartInfo.lpReserved = NULL;
\r
9212 siStartInfo.lpDesktop = NULL;
\r
9213 siStartInfo.lpTitle = NULL;
\r
9214 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9215 siStartInfo.cbReserved2 = 0;
\r
9216 siStartInfo.lpReserved2 = NULL;
\r
9217 siStartInfo.hStdInput = hChildStdinRd;
\r
9218 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9219 siStartInfo.hStdError = hChildStdoutWr;
\r
9221 fSuccess = CreateProcess(NULL,
\r
9222 cmdLine, /* command line */
\r
9223 NULL, /* process security attributes */
\r
9224 NULL, /* primary thread security attrs */
\r
9225 TRUE, /* handles are inherited */
\r
9226 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9227 NULL, /* use parent's environment */
\r
9229 &siStartInfo, /* STARTUPINFO pointer */
\r
9230 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9232 err = GetLastError();
\r
9233 SetCurrentDirectory(buf); /* return to prev directory */
\r
9238 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9239 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9240 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9243 /* Close the handles we don't need in the parent */
\r
9244 CloseHandle(piProcInfo.hThread);
\r
9245 CloseHandle(hChildStdinRd);
\r
9246 CloseHandle(hChildStdoutWr);
\r
9248 /* Prepare return value */
\r
9249 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9250 cp->kind = CPReal;
\r
9251 cp->hProcess = piProcInfo.hProcess;
\r
9252 cp->pid = piProcInfo.dwProcessId;
\r
9253 cp->hFrom = hChildStdoutRdDup;
\r
9254 cp->hTo = hChildStdinWrDup;
\r
9256 *pr = (void *) cp;
\r
9258 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9259 2000 where engines sometimes don't see the initial command(s)
\r
9260 from WinBoard and hang. I don't understand how that can happen,
\r
9261 but the Sleep is harmless, so I've put it in. Others have also
\r
9262 reported what may be the same problem, so hopefully this will fix
\r
9263 it for them too. */
\r
9271 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9273 ChildProc *cp; int result;
\r
9275 cp = (ChildProc *) pr;
\r
9276 if (cp == NULL) return;
\r
9278 switch (cp->kind) {
\r
9280 /* TerminateProcess is considered harmful, so... */
\r
9281 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9282 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9283 /* The following doesn't work because the chess program
\r
9284 doesn't "have the same console" as WinBoard. Maybe
\r
9285 we could arrange for this even though neither WinBoard
\r
9286 nor the chess program uses a console for stdio? */
\r
9287 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9289 /* [AS] Special termination modes for misbehaving programs... */
\r
9290 if( signal & 8 ) {
\r
9291 result = TerminateProcess( cp->hProcess, 0 );
\r
9293 if ( appData.debugMode) {
\r
9294 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9297 else if( signal & 4 ) {
\r
9298 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9300 if( dw != WAIT_OBJECT_0 ) {
\r
9301 result = TerminateProcess( cp->hProcess, 0 );
\r
9303 if ( appData.debugMode) {
\r
9304 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9310 CloseHandle(cp->hProcess);
\r
9314 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9318 closesocket(cp->sock);
\r
9323 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9324 closesocket(cp->sock);
\r
9325 closesocket(cp->sock2);
\r
9333 InterruptChildProcess(ProcRef pr)
\r
9337 cp = (ChildProc *) pr;
\r
9338 if (cp == NULL) return;
\r
9339 switch (cp->kind) {
\r
9341 /* The following doesn't work because the chess program
\r
9342 doesn't "have the same console" as WinBoard. Maybe
\r
9343 we could arrange for this even though neither WinBoard
\r
9344 nor the chess program uses a console for stdio */
\r
9345 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9350 /* Can't interrupt */
\r
9354 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9361 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9363 char cmdLine[MSG_SIZ];
\r
9365 if (port[0] == NULLCHAR) {
\r
9366 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9368 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9370 return StartChildProcess(cmdLine, "", pr);
\r
9374 /* Code to open TCP sockets */
\r
9377 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9383 struct sockaddr_in sa, mysa;
\r
9384 struct hostent FAR *hp;
\r
9385 unsigned short uport;
\r
9386 WORD wVersionRequested;
\r
9389 /* Initialize socket DLL */
\r
9390 wVersionRequested = MAKEWORD(1, 1);
\r
9391 err = WSAStartup(wVersionRequested, &wsaData);
\r
9392 if (err != 0) return err;
\r
9395 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9396 err = WSAGetLastError();
\r
9401 /* Bind local address using (mostly) don't-care values.
\r
9403 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9404 mysa.sin_family = AF_INET;
\r
9405 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9406 uport = (unsigned short) 0;
\r
9407 mysa.sin_port = htons(uport);
\r
9408 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9409 == SOCKET_ERROR) {
\r
9410 err = WSAGetLastError();
\r
9415 /* Resolve remote host name */
\r
9416 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9417 if (!(hp = gethostbyname(host))) {
\r
9418 unsigned int b0, b1, b2, b3;
\r
9420 err = WSAGetLastError();
\r
9422 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9423 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9424 hp->h_addrtype = AF_INET;
\r
9426 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9427 hp->h_addr_list[0] = (char *) malloc(4);
\r
9428 hp->h_addr_list[0][0] = (char) b0;
\r
9429 hp->h_addr_list[0][1] = (char) b1;
\r
9430 hp->h_addr_list[0][2] = (char) b2;
\r
9431 hp->h_addr_list[0][3] = (char) b3;
\r
9437 sa.sin_family = hp->h_addrtype;
\r
9438 uport = (unsigned short) atoi(port);
\r
9439 sa.sin_port = htons(uport);
\r
9440 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9442 /* Make connection */
\r
9443 if (connect(s, (struct sockaddr *) &sa,
\r
9444 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9445 err = WSAGetLastError();
\r
9450 /* Prepare return value */
\r
9451 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9452 cp->kind = CPSock;
\r
9454 *pr = (ProcRef *) cp;
\r
9460 OpenCommPort(char *name, ProcRef *pr)
\r
9465 char fullname[MSG_SIZ];
\r
9467 if (*name != '\\')
\r
9468 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9470 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9472 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9473 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9474 if (h == (HANDLE) -1) {
\r
9475 return GetLastError();
\r
9479 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9481 /* Accumulate characters until a 100ms pause, then parse */
\r
9482 ct.ReadIntervalTimeout = 100;
\r
9483 ct.ReadTotalTimeoutMultiplier = 0;
\r
9484 ct.ReadTotalTimeoutConstant = 0;
\r
9485 ct.WriteTotalTimeoutMultiplier = 0;
\r
9486 ct.WriteTotalTimeoutConstant = 0;
\r
9487 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9489 /* Prepare return value */
\r
9490 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9491 cp->kind = CPComm;
\r
9494 *pr = (ProcRef *) cp;
\r
9500 OpenLoopback(ProcRef *pr)
\r
9502 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9508 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9513 struct sockaddr_in sa, mysa;
\r
9514 struct hostent FAR *hp;
\r
9515 unsigned short uport;
\r
9516 WORD wVersionRequested;
\r
9519 char stderrPortStr[MSG_SIZ];
\r
9521 /* Initialize socket DLL */
\r
9522 wVersionRequested = MAKEWORD(1, 1);
\r
9523 err = WSAStartup(wVersionRequested, &wsaData);
\r
9524 if (err != 0) return err;
\r
9526 /* Resolve remote host name */
\r
9527 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9528 if (!(hp = gethostbyname(host))) {
\r
9529 unsigned int b0, b1, b2, b3;
\r
9531 err = WSAGetLastError();
\r
9533 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9534 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9535 hp->h_addrtype = AF_INET;
\r
9537 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9538 hp->h_addr_list[0] = (char *) malloc(4);
\r
9539 hp->h_addr_list[0][0] = (char) b0;
\r
9540 hp->h_addr_list[0][1] = (char) b1;
\r
9541 hp->h_addr_list[0][2] = (char) b2;
\r
9542 hp->h_addr_list[0][3] = (char) b3;
\r
9548 sa.sin_family = hp->h_addrtype;
\r
9549 uport = (unsigned short) 514;
\r
9550 sa.sin_port = htons(uport);
\r
9551 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9553 /* Bind local socket to unused "privileged" port address
\r
9555 s = INVALID_SOCKET;
\r
9556 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9557 mysa.sin_family = AF_INET;
\r
9558 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9559 for (fromPort = 1023;; fromPort--) {
\r
9560 if (fromPort < 0) {
\r
9562 return WSAEADDRINUSE;
\r
9564 if (s == INVALID_SOCKET) {
\r
9565 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9566 err = WSAGetLastError();
\r
9571 uport = (unsigned short) fromPort;
\r
9572 mysa.sin_port = htons(uport);
\r
9573 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9574 == SOCKET_ERROR) {
\r
9575 err = WSAGetLastError();
\r
9576 if (err == WSAEADDRINUSE) continue;
\r
9580 if (connect(s, (struct sockaddr *) &sa,
\r
9581 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9582 err = WSAGetLastError();
\r
9583 if (err == WSAEADDRINUSE) {
\r
9594 /* Bind stderr local socket to unused "privileged" port address
\r
9596 s2 = INVALID_SOCKET;
\r
9597 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9598 mysa.sin_family = AF_INET;
\r
9599 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9600 for (fromPort = 1023;; fromPort--) {
\r
9601 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9602 if (fromPort < 0) {
\r
9603 (void) closesocket(s);
\r
9605 return WSAEADDRINUSE;
\r
9607 if (s2 == INVALID_SOCKET) {
\r
9608 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9609 err = WSAGetLastError();
\r
9615 uport = (unsigned short) fromPort;
\r
9616 mysa.sin_port = htons(uport);
\r
9617 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9618 == SOCKET_ERROR) {
\r
9619 err = WSAGetLastError();
\r
9620 if (err == WSAEADDRINUSE) continue;
\r
9621 (void) closesocket(s);
\r
9625 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9626 err = WSAGetLastError();
\r
9627 if (err == WSAEADDRINUSE) {
\r
9629 s2 = INVALID_SOCKET;
\r
9632 (void) closesocket(s);
\r
9633 (void) closesocket(s2);
\r
9639 prevStderrPort = fromPort; // remember port used
\r
9640 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9642 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9643 err = WSAGetLastError();
\r
9644 (void) closesocket(s);
\r
9645 (void) closesocket(s2);
\r
9650 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9651 err = WSAGetLastError();
\r
9652 (void) closesocket(s);
\r
9653 (void) closesocket(s2);
\r
9657 if (*user == NULLCHAR) user = UserName();
\r
9658 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9659 err = WSAGetLastError();
\r
9660 (void) closesocket(s);
\r
9661 (void) closesocket(s2);
\r
9665 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9666 err = WSAGetLastError();
\r
9667 (void) closesocket(s);
\r
9668 (void) closesocket(s2);
\r
9673 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9674 err = WSAGetLastError();
\r
9675 (void) closesocket(s);
\r
9676 (void) closesocket(s2);
\r
9680 (void) closesocket(s2); /* Stop listening */
\r
9682 /* Prepare return value */
\r
9683 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9684 cp->kind = CPRcmd;
\r
9687 *pr = (ProcRef *) cp;
\r
9694 AddInputSource(ProcRef pr, int lineByLine,
\r
9695 InputCallback func, VOIDSTAR closure)
\r
9697 InputSource *is, *is2 = NULL;
\r
9698 ChildProc *cp = (ChildProc *) pr;
\r
9700 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9701 is->lineByLine = lineByLine;
\r
9703 is->closure = closure;
\r
9704 is->second = NULL;
\r
9705 is->next = is->buf;
\r
9706 if (pr == NoProc) {
\r
9707 is->kind = CPReal;
\r
9708 consoleInputSource = is;
\r
9710 is->kind = cp->kind;
\r
9712 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9713 we create all threads suspended so that the is->hThread variable can be
\r
9714 safely assigned, then let the threads start with ResumeThread.
\r
9716 switch (cp->kind) {
\r
9718 is->hFile = cp->hFrom;
\r
9719 cp->hFrom = NULL; /* now owned by InputThread */
\r
9721 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9722 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9726 is->hFile = cp->hFrom;
\r
9727 cp->hFrom = NULL; /* now owned by InputThread */
\r
9729 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9730 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9734 is->sock = cp->sock;
\r
9736 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9737 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9741 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9743 is->sock = cp->sock;
\r
9745 is2->sock = cp->sock2;
\r
9746 is2->second = is2;
\r
9748 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9749 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9751 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9752 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9756 if( is->hThread != NULL ) {
\r
9757 ResumeThread( is->hThread );
\r
9760 if( is2 != NULL && is2->hThread != NULL ) {
\r
9761 ResumeThread( is2->hThread );
\r
9765 return (InputSourceRef) is;
\r
9769 RemoveInputSource(InputSourceRef isr)
\r
9773 is = (InputSource *) isr;
\r
9774 is->hThread = NULL; /* tell thread to stop */
\r
9775 CloseHandle(is->hThread);
\r
9776 if (is->second != NULL) {
\r
9777 is->second->hThread = NULL;
\r
9778 CloseHandle(is->second->hThread);
\r
9782 int no_wrap(char *message, int count)
\r
9784 ConsoleOutput(message, count, FALSE);
\r
9789 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9792 int outCount = SOCKET_ERROR;
\r
9793 ChildProc *cp = (ChildProc *) pr;
\r
9794 static OVERLAPPED ovl;
\r
9796 static int line = 0;
\r
9800 if (appData.noJoin || !appData.useInternalWrap)
\r
9801 return no_wrap(message, count);
\r
9804 int width = get_term_width();
\r
9805 int len = wrap(NULL, message, count, width, &line);
\r
9806 char *msg = malloc(len);
\r
9810 return no_wrap(message, count);
\r
9813 dbgchk = wrap(msg, message, count, width, &line);
\r
9814 if (dbgchk != len && appData.debugMode)
\r
9815 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9816 ConsoleOutput(msg, len, FALSE);
\r
9823 if (ovl.hEvent == NULL) {
\r
9824 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9826 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9828 switch (cp->kind) {
\r
9831 outCount = send(cp->sock, message, count, 0);
\r
9832 if (outCount == SOCKET_ERROR) {
\r
9833 *outError = WSAGetLastError();
\r
9835 *outError = NO_ERROR;
\r
9840 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9841 &dOutCount, NULL)) {
\r
9842 *outError = NO_ERROR;
\r
9843 outCount = (int) dOutCount;
\r
9845 *outError = GetLastError();
\r
9850 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9851 &dOutCount, &ovl);
\r
9852 if (*outError == NO_ERROR) {
\r
9853 outCount = (int) dOutCount;
\r
9863 if(n != 0) Sleep(n);
\r
9867 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9870 /* Ignore delay, not implemented for WinBoard */
\r
9871 return OutputToProcess(pr, message, count, outError);
\r
9876 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9877 char *buf, int count, int error)
\r
9879 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9882 /* see wgamelist.c for Game List functions */
\r
9883 /* see wedittags.c for Edit Tags functions */
\r
9890 char buf[MSG_SIZ];
\r
9893 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9894 f = fopen(buf, "r");
\r
9896 ProcessICSInitScript(f);
\r
9906 StartAnalysisClock()
\r
9908 if (analysisTimerEvent) return;
\r
9909 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9910 (UINT) 2000, NULL);
\r
9914 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9916 highlightInfo.sq[0].x = fromX;
\r
9917 highlightInfo.sq[0].y = fromY;
\r
9918 highlightInfo.sq[1].x = toX;
\r
9919 highlightInfo.sq[1].y = toY;
\r
9925 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9926 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9930 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9932 premoveHighlightInfo.sq[0].x = fromX;
\r
9933 premoveHighlightInfo.sq[0].y = fromY;
\r
9934 premoveHighlightInfo.sq[1].x = toX;
\r
9935 premoveHighlightInfo.sq[1].y = toY;
\r
9939 ClearPremoveHighlights()
\r
9941 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9942 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9946 ShutDownFrontEnd()
\r
9948 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9949 DeleteClipboardTempFiles();
\r
9955 if (IsIconic(hwndMain))
\r
9956 ShowWindow(hwndMain, SW_RESTORE);
\r
9958 SetActiveWindow(hwndMain);
\r
9962 * Prototypes for animation support routines
\r
9964 static void ScreenSquare(int column, int row, POINT * pt);
\r
9965 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9966 POINT frames[], int * nFrames);
\r
9972 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9973 { // [HGM] atomic: animate blast wave
\r
9976 explodeInfo.fromX = fromX;
\r
9977 explodeInfo.fromY = fromY;
\r
9978 explodeInfo.toX = toX;
\r
9979 explodeInfo.toY = toY;
\r
9980 for(i=1; i<4*kFactor; i++) {
\r
9981 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9982 DrawPosition(FALSE, board);
\r
9983 Sleep(appData.animSpeed);
\r
9985 explodeInfo.radius = 0;
\r
9986 DrawPosition(TRUE, board);
\r
9990 AnimateMove(board, fromX, fromY, toX, toY)
\r
9997 ChessSquare piece;
\r
9998 int x = toX, y = toY;
\r
9999 POINT start, finish, mid;
\r
10000 POINT frames[kFactor * 2 + 1];
\r
10003 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
10005 if (!appData.animate) return;
\r
10006 if (doingSizing) return;
\r
10007 if (fromY < 0 || fromX < 0) return;
\r
10008 piece = board[fromY][fromX];
\r
10009 if (piece >= EmptySquare) return;
\r
10011 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10015 ScreenSquare(fromX, fromY, &start);
\r
10016 ScreenSquare(toX, toY, &finish);
\r
10018 /* All moves except knight jumps move in straight line */
\r
10019 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10020 mid.x = start.x + (finish.x - start.x) / 2;
\r
10021 mid.y = start.y + (finish.y - start.y) / 2;
\r
10023 /* Knight: make straight movement then diagonal */
\r
10024 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10025 mid.x = start.x + (finish.x - start.x) / 2;
\r
10029 mid.y = start.y + (finish.y - start.y) / 2;
\r
10033 /* Don't use as many frames for very short moves */
\r
10034 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10035 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10037 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10039 animInfo.from.x = fromX;
\r
10040 animInfo.from.y = fromY;
\r
10041 animInfo.to.x = toX;
\r
10042 animInfo.to.y = toY;
\r
10043 animInfo.lastpos = start;
\r
10044 animInfo.piece = piece;
\r
10045 for (n = 0; n < nFrames; n++) {
\r
10046 animInfo.pos = frames[n];
\r
10047 DrawPosition(FALSE, NULL);
\r
10048 animInfo.lastpos = animInfo.pos;
\r
10049 Sleep(appData.animSpeed);
\r
10051 animInfo.pos = finish;
\r
10052 DrawPosition(FALSE, NULL);
\r
10054 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10056 animInfo.piece = EmptySquare;
\r
10057 Explode(board, fromX, fromY, toX, toY);
\r
10060 /* Convert board position to corner of screen rect and color */
\r
10063 ScreenSquare(column, row, pt)
\r
10064 int column; int row; POINT * pt;
\r
10067 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10068 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10070 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10071 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10075 /* Generate a series of frame coords from start->mid->finish.
\r
10076 The movement rate doubles until the half way point is
\r
10077 reached, then halves back down to the final destination,
\r
10078 which gives a nice slow in/out effect. The algorithmn
\r
10079 may seem to generate too many intermediates for short
\r
10080 moves, but remember that the purpose is to attract the
\r
10081 viewers attention to the piece about to be moved and
\r
10082 then to where it ends up. Too few frames would be less
\r
10086 Tween(start, mid, finish, factor, frames, nFrames)
\r
10087 POINT * start; POINT * mid;
\r
10088 POINT * finish; int factor;
\r
10089 POINT frames[]; int * nFrames;
\r
10091 int n, fraction = 1, count = 0;
\r
10093 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10094 for (n = 0; n < factor; n++)
\r
10096 for (n = 0; n < factor; n++) {
\r
10097 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10098 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10100 fraction = fraction / 2;
\r
10104 frames[count] = *mid;
\r
10107 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10109 for (n = 0; n < factor; n++) {
\r
10110 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10111 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10113 fraction = fraction * 2;
\r
10115 *nFrames = count;
\r
10119 SettingsPopUp(ChessProgramState *cps)
\r
10120 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10121 EngineOptionsPopup(savedHwnd, cps);
\r
10124 int flock(int fid, int code)
\r
10126 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10128 ov.hEvent = NULL;
\r
10130 ov.OffsetHigh = 0;
\r
10132 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10134 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10135 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10136 default: return -1;
\r
10145 static char col[8][20];
\r
10146 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10148 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10153 ActivateTheme (int new)
\r
10154 { // Redo initialization of features depending on options that can occur in themes
\r
10156 if(new) InitDrawingColors();
\r
10157 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10158 InitDrawingSizes(boardSize, 0);
\r
10159 InvalidateRect(hwndMain, NULL, TRUE);
\r