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 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5097 case IDM_TwoMachines:
\r
5098 TwoMachinesEvent();
\r
5101 * refresh the tags dialog only if it's visible
\r
5103 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5105 tags = PGNTags(&gameInfo);
\r
5106 TagsPopUp(tags, CmailMsg());
\r
5109 SAY("computer starts playing both sides");
\r
5112 case IDM_AnalysisMode:
\r
5113 if(AnalyzeModeEvent()) {
\r
5114 SAY("analyzing current position");
\r
5118 case IDM_AnalyzeFile:
\r
5119 AnalyzeFileEvent();
\r
5122 case IDM_IcsClient:
\r
5126 case IDM_EditGame:
\r
5127 case IDM_EditGame2:
\r
5132 case IDM_EditPosition:
\r
5133 case IDM_EditPosition2:
\r
5134 EditPositionEvent();
\r
5135 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5138 case IDM_Training:
\r
5142 case IDM_ShowGameList:
\r
5143 ShowGameListProc();
\r
5146 case IDM_EditProgs1:
\r
5147 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5150 case IDM_LoadProg1:
\r
5151 LoadEnginePopUp(hwndMain, 0);
\r
5154 case IDM_LoadProg2:
\r
5155 LoadEnginePopUp(hwndMain, 1);
\r
5158 case IDM_EditServers:
\r
5159 EditTagsPopUp(icsNames, &icsNames);
\r
5162 case IDM_EditTags:
\r
5167 case IDM_EditBook:
\r
5171 case IDM_EditComment:
\r
5173 if (commentUp && editComment) {
\r
5176 EditCommentEvent();
\r
5197 case IDM_CallFlag:
\r
5217 case IDM_StopObserving:
\r
5218 StopObservingEvent();
\r
5221 case IDM_StopExamining:
\r
5222 StopExaminingEvent();
\r
5226 UploadGameEvent();
\r
5229 case IDM_TypeInMove:
\r
5230 TypeInEvent('\000');
\r
5233 case IDM_TypeInName:
\r
5234 PopUpNameDialog('\000');
\r
5237 case IDM_Backward:
\r
5239 SetFocus(hwndMain);
\r
5246 SetFocus(hwndMain);
\r
5251 SetFocus(hwndMain);
\r
5256 SetFocus(hwndMain);
\r
5259 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5260 case OPT_GameListPrev:
\r
5261 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5265 RevertEvent(FALSE);
\r
5268 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5269 RevertEvent(TRUE);
\r
5272 case IDM_TruncateGame:
\r
5273 TruncateGameEvent();
\r
5280 case IDM_RetractMove:
\r
5281 RetractMoveEvent();
\r
5284 case IDM_FlipView:
\r
5285 flipView = !flipView;
\r
5286 DrawPosition(FALSE, NULL);
\r
5289 case IDM_FlipClock:
\r
5290 flipClock = !flipClock;
\r
5291 DisplayBothClocks();
\r
5295 case IDM_MuteSounds:
\r
5296 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5297 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5298 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5301 case IDM_GeneralOptions:
\r
5302 GeneralOptionsPopup(hwnd);
\r
5303 DrawPosition(TRUE, NULL);
\r
5306 case IDM_BoardOptions:
\r
5307 BoardOptionsPopup(hwnd);
\r
5310 case IDM_ThemeOptions:
\r
5311 ThemeOptionsPopup(hwnd);
\r
5314 case IDM_EnginePlayOptions:
\r
5315 EnginePlayOptionsPopup(hwnd);
\r
5318 case IDM_Engine1Options:
\r
5319 EngineOptionsPopup(hwnd, &first);
\r
5322 case IDM_Engine2Options:
\r
5324 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5325 EngineOptionsPopup(hwnd, &second);
\r
5328 case IDM_OptionsUCI:
\r
5329 UciOptionsPopup(hwnd);
\r
5333 TourneyPopup(hwnd);
\r
5336 case IDM_IcsOptions:
\r
5337 IcsOptionsPopup(hwnd);
\r
5341 FontsOptionsPopup(hwnd);
\r
5345 SoundOptionsPopup(hwnd);
\r
5348 case IDM_CommPort:
\r
5349 CommPortOptionsPopup(hwnd);
\r
5352 case IDM_LoadOptions:
\r
5353 LoadOptionsPopup(hwnd);
\r
5356 case IDM_SaveOptions:
\r
5357 SaveOptionsPopup(hwnd);
\r
5360 case IDM_TimeControl:
\r
5361 TimeControlOptionsPopup(hwnd);
\r
5364 case IDM_SaveSettings:
\r
5365 SaveSettings(settingsFileName);
\r
5368 case IDM_SaveSettingsOnExit:
\r
5369 saveSettingsOnExit = !saveSettingsOnExit;
\r
5370 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5371 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5372 MF_CHECKED : MF_UNCHECKED));
\r
5383 case IDM_AboutGame:
\r
5388 appData.debugMode = !appData.debugMode;
\r
5389 if (appData.debugMode) {
\r
5390 char dir[MSG_SIZ];
\r
5391 GetCurrentDirectory(MSG_SIZ, dir);
\r
5392 SetCurrentDirectory(installDir);
\r
5393 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5394 SetCurrentDirectory(dir);
\r
5395 setbuf(debugFP, NULL);
\r
5402 case IDM_HELPCONTENTS:
\r
5403 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5404 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5405 MessageBox (GetFocus(),
\r
5406 _("Unable to activate help"),
\r
5407 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5411 case IDM_HELPSEARCH:
\r
5412 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5413 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5414 MessageBox (GetFocus(),
\r
5415 _("Unable to activate help"),
\r
5416 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5420 case IDM_HELPHELP:
\r
5421 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5422 MessageBox (GetFocus(),
\r
5423 _("Unable to activate help"),
\r
5424 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5429 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5431 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5432 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5433 FreeProcInstance(lpProc);
\r
5436 case IDM_DirectCommand1:
\r
5437 AskQuestionEvent(_("Direct Command"),
\r
5438 _("Send to chess program:"), "", "1");
\r
5440 case IDM_DirectCommand2:
\r
5441 AskQuestionEvent(_("Direct Command"),
\r
5442 _("Send to second chess program:"), "", "2");
\r
5445 case EP_WhitePawn:
\r
5446 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5447 fromX = fromY = -1;
\r
5450 case EP_WhiteKnight:
\r
5451 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5452 fromX = fromY = -1;
\r
5455 case EP_WhiteBishop:
\r
5456 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5457 fromX = fromY = -1;
\r
5460 case EP_WhiteRook:
\r
5461 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5462 fromX = fromY = -1;
\r
5465 case EP_WhiteQueen:
\r
5466 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5467 fromX = fromY = -1;
\r
5470 case EP_WhiteFerz:
\r
5471 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5472 fromX = fromY = -1;
\r
5475 case EP_WhiteWazir:
\r
5476 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5477 fromX = fromY = -1;
\r
5480 case EP_WhiteAlfil:
\r
5481 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5482 fromX = fromY = -1;
\r
5485 case EP_WhiteCannon:
\r
5486 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5487 fromX = fromY = -1;
\r
5490 case EP_WhiteCardinal:
\r
5491 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5492 fromX = fromY = -1;
\r
5495 case EP_WhiteMarshall:
\r
5496 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5497 fromX = fromY = -1;
\r
5500 case EP_WhiteKing:
\r
5501 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5502 fromX = fromY = -1;
\r
5505 case EP_BlackPawn:
\r
5506 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5507 fromX = fromY = -1;
\r
5510 case EP_BlackKnight:
\r
5511 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5512 fromX = fromY = -1;
\r
5515 case EP_BlackBishop:
\r
5516 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5520 case EP_BlackRook:
\r
5521 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5522 fromX = fromY = -1;
\r
5525 case EP_BlackQueen:
\r
5526 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5527 fromX = fromY = -1;
\r
5530 case EP_BlackFerz:
\r
5531 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5532 fromX = fromY = -1;
\r
5535 case EP_BlackWazir:
\r
5536 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5537 fromX = fromY = -1;
\r
5540 case EP_BlackAlfil:
\r
5541 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5542 fromX = fromY = -1;
\r
5545 case EP_BlackCannon:
\r
5546 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5547 fromX = fromY = -1;
\r
5550 case EP_BlackCardinal:
\r
5551 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5552 fromX = fromY = -1;
\r
5555 case EP_BlackMarshall:
\r
5556 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5557 fromX = fromY = -1;
\r
5560 case EP_BlackKing:
\r
5561 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5562 fromX = fromY = -1;
\r
5565 case EP_EmptySquare:
\r
5566 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5567 fromX = fromY = -1;
\r
5570 case EP_ClearBoard:
\r
5571 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5572 fromX = fromY = -1;
\r
5576 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5577 fromX = fromY = -1;
\r
5581 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5582 fromX = fromY = -1;
\r
5586 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5587 fromX = fromY = -1;
\r
5591 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5592 fromX = fromY = -1;
\r
5596 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5597 fromX = fromY = -1;
\r
5601 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5602 fromX = fromY = -1;
\r
5606 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5607 fromX = fromY = -1;
\r
5611 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5612 fromX = fromY = -1;
\r
5616 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5617 fromX = fromY = -1;
\r
5621 barbaric = 0; appData.language = "";
\r
5622 TranslateMenus(0);
\r
5623 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5624 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5625 lastChecked = wmId;
\r
5629 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5630 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5632 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5633 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5634 TranslateMenus(0);
\r
5635 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5636 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5637 lastChecked = wmId;
\r
5640 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5646 case CLOCK_TIMER_ID:
\r
5647 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5648 clockTimerEvent = 0;
\r
5649 DecrementClocks(); /* call into back end */
\r
5651 case LOAD_GAME_TIMER_ID:
\r
5652 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5653 loadGameTimerEvent = 0;
\r
5654 AutoPlayGameLoop(); /* call into back end */
\r
5656 case ANALYSIS_TIMER_ID:
\r
5657 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5658 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5659 AnalysisPeriodicEvent(0);
\r
5661 KillTimer(hwnd, analysisTimerEvent);
\r
5662 analysisTimerEvent = 0;
\r
5665 case DELAYED_TIMER_ID:
\r
5666 KillTimer(hwnd, delayedTimerEvent);
\r
5667 delayedTimerEvent = 0;
\r
5668 delayedTimerCallback();
\r
5673 case WM_USER_Input:
\r
5674 InputEvent(hwnd, message, wParam, lParam);
\r
5677 /* [AS] Also move "attached" child windows */
\r
5678 case WM_WINDOWPOSCHANGING:
\r
5680 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5681 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5683 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5684 /* Window is moving */
\r
5687 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5688 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5689 rcMain.right = wpMain.x + wpMain.width;
\r
5690 rcMain.top = wpMain.y;
\r
5691 rcMain.bottom = wpMain.y + wpMain.height;
\r
5693 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5694 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5695 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5696 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5697 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5698 wpMain.x = lpwp->x;
\r
5699 wpMain.y = lpwp->y;
\r
5704 /* [AS] Snapping */
\r
5705 case WM_ENTERSIZEMOVE:
\r
5706 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5707 if (hwnd == hwndMain) {
\r
5708 doingSizing = TRUE;
\r
5711 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5715 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5716 if (hwnd == hwndMain) {
\r
5717 lastSizing = wParam;
\r
5722 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5723 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5725 case WM_EXITSIZEMOVE:
\r
5726 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5727 if (hwnd == hwndMain) {
\r
5729 doingSizing = FALSE;
\r
5730 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5731 GetClientRect(hwnd, &client);
\r
5732 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5734 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5736 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5739 case WM_DESTROY: /* message: window being destroyed */
\r
5740 PostQuitMessage(0);
\r
5744 if (hwnd == hwndMain) {
\r
5749 default: /* Passes it on if unprocessed */
\r
5750 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5757 /*---------------------------------------------------------------------------*\
\r
5759 * Misc utility routines
\r
5761 \*---------------------------------------------------------------------------*/
\r
5764 * Decent random number generator, at least not as bad as Windows
\r
5765 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5767 unsigned int randstate;
\r
5772 randstate = randstate * 1664525 + 1013904223;
\r
5773 return (int) randstate & 0x7fffffff;
\r
5777 mysrandom(unsigned int seed)
\r
5784 * returns TRUE if user selects a different color, FALSE otherwise
\r
5788 ChangeColor(HWND hwnd, COLORREF *which)
\r
5790 static BOOL firstTime = TRUE;
\r
5791 static DWORD customColors[16];
\r
5793 COLORREF newcolor;
\r
5798 /* Make initial colors in use available as custom colors */
\r
5799 /* Should we put the compiled-in defaults here instead? */
\r
5801 customColors[i++] = lightSquareColor & 0xffffff;
\r
5802 customColors[i++] = darkSquareColor & 0xffffff;
\r
5803 customColors[i++] = whitePieceColor & 0xffffff;
\r
5804 customColors[i++] = blackPieceColor & 0xffffff;
\r
5805 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5806 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5808 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5809 customColors[i++] = textAttribs[ccl].color;
\r
5811 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5812 firstTime = FALSE;
\r
5815 cc.lStructSize = sizeof(cc);
\r
5816 cc.hwndOwner = hwnd;
\r
5817 cc.hInstance = NULL;
\r
5818 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5819 cc.lpCustColors = (LPDWORD) customColors;
\r
5820 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5822 if (!ChooseColor(&cc)) return FALSE;
\r
5824 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5825 if (newcolor == *which) return FALSE;
\r
5826 *which = newcolor;
\r
5830 InitDrawingColors();
\r
5831 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5836 MyLoadSound(MySound *ms)
\r
5842 if (ms->data && ms->flag) free(ms->data);
\r
5845 switch (ms->name[0]) {
\r
5851 /* System sound from Control Panel. Don't preload here. */
\r
5855 if (ms->name[1] == NULLCHAR) {
\r
5856 /* "!" alone = silence */
\r
5859 /* Builtin wave resource. Error if not found. */
\r
5860 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5861 if (h == NULL) break;
\r
5862 ms->data = (void *)LoadResource(hInst, h);
\r
5863 ms->flag = 0; // not maloced, so cannot be freed!
\r
5864 if (h == NULL) break;
\r
5869 /* .wav file. Error if not found. */
\r
5870 f = fopen(ms->name, "rb");
\r
5871 if (f == NULL) break;
\r
5872 if (fstat(fileno(f), &st) < 0) break;
\r
5873 ms->data = malloc(st.st_size);
\r
5875 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5881 char buf[MSG_SIZ];
\r
5882 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5883 DisplayError(buf, GetLastError());
\r
5889 MyPlaySound(MySound *ms)
\r
5891 BOOLEAN ok = FALSE;
\r
5893 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5894 switch (ms->name[0]) {
\r
5896 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5901 /* System sound from Control Panel (deprecated feature).
\r
5902 "$" alone or an unset sound name gets default beep (still in use). */
\r
5903 if (ms->name[1]) {
\r
5904 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5906 if (!ok) ok = MessageBeep(MB_OK);
\r
5909 /* Builtin wave resource, or "!" alone for silence */
\r
5910 if (ms->name[1]) {
\r
5911 if (ms->data == NULL) return FALSE;
\r
5912 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5918 /* .wav file. Error if not found. */
\r
5919 if (ms->data == NULL) return FALSE;
\r
5920 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5923 /* Don't print an error: this can happen innocently if the sound driver
\r
5924 is busy; for instance, if another instance of WinBoard is playing
\r
5925 a sound at about the same time. */
\r
5931 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5934 OPENFILENAME *ofn;
\r
5935 static UINT *number; /* gross that this is static */
\r
5937 switch (message) {
\r
5938 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5939 /* Center the dialog over the application window */
\r
5940 ofn = (OPENFILENAME *) lParam;
\r
5941 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5942 number = (UINT *) ofn->lCustData;
\r
5943 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5947 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5948 Translate(hDlg, 1536);
\r
5949 return FALSE; /* Allow for further processing */
\r
5952 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5953 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5955 return FALSE; /* Allow for further processing */
\r
5961 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5963 static UINT *number;
\r
5964 OPENFILENAME *ofname;
\r
5967 case WM_INITDIALOG:
\r
5968 Translate(hdlg, DLG_IndexNumber);
\r
5969 ofname = (OPENFILENAME *)lParam;
\r
5970 number = (UINT *)(ofname->lCustData);
\r
5973 ofnot = (OFNOTIFY *)lParam;
\r
5974 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5975 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5984 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5985 char *nameFilt, char *dlgTitle, UINT *number,
\r
5986 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5988 OPENFILENAME openFileName;
\r
5989 char buf1[MSG_SIZ];
\r
5992 if (fileName == NULL) fileName = buf1;
\r
5993 if (defName == NULL) {
\r
5994 safeStrCpy(fileName, "*.", 3 );
\r
5995 strcat(fileName, defExt);
\r
5997 safeStrCpy(fileName, defName, MSG_SIZ );
\r
5999 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
6000 if (number) *number = 0;
\r
6002 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6003 openFileName.hwndOwner = hwnd;
\r
6004 openFileName.hInstance = (HANDLE) hInst;
\r
6005 openFileName.lpstrFilter = nameFilt;
\r
6006 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6007 openFileName.nMaxCustFilter = 0L;
\r
6008 openFileName.nFilterIndex = 1L;
\r
6009 openFileName.lpstrFile = fileName;
\r
6010 openFileName.nMaxFile = MSG_SIZ;
\r
6011 openFileName.lpstrFileTitle = fileTitle;
\r
6012 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6013 openFileName.lpstrInitialDir = NULL;
\r
6014 openFileName.lpstrTitle = dlgTitle;
\r
6015 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6016 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6017 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6018 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6019 openFileName.nFileOffset = 0;
\r
6020 openFileName.nFileExtension = 0;
\r
6021 openFileName.lpstrDefExt = defExt;
\r
6022 openFileName.lCustData = (LONG) number;
\r
6023 openFileName.lpfnHook = oldDialog ?
\r
6024 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6025 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6027 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6028 GetOpenFileName(&openFileName)) {
\r
6029 /* open the file */
\r
6030 f = fopen(openFileName.lpstrFile, write);
\r
6032 MessageBox(hwnd, _("File open failed"), NULL,
\r
6033 MB_OK|MB_ICONEXCLAMATION);
\r
6037 int err = CommDlgExtendedError();
\r
6038 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6047 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6049 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6052 * Get the first pop-up menu in the menu template. This is the
\r
6053 * menu that TrackPopupMenu displays.
\r
6055 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6056 TranslateOneMenu(10, hmenuTrackPopup);
\r
6058 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6061 * TrackPopup uses screen coordinates, so convert the
\r
6062 * coordinates of the mouse click to screen coordinates.
\r
6064 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6066 /* Draw and track the floating pop-up menu. */
\r
6067 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6068 pt.x, pt.y, 0, hwnd, NULL);
\r
6070 /* Destroy the menu.*/
\r
6071 DestroyMenu(hmenu);
\r
6076 int sizeX, sizeY, newSizeX, newSizeY;
\r
6078 } ResizeEditPlusButtonsClosure;
\r
6081 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6083 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6087 if (hChild == cl->hText) return TRUE;
\r
6088 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6089 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6090 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6091 ScreenToClient(cl->hDlg, &pt);
\r
6092 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6093 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6097 /* Resize a dialog that has a (rich) edit field filling most of
\r
6098 the top, with a row of buttons below */
\r
6100 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6103 int newTextHeight, newTextWidth;
\r
6104 ResizeEditPlusButtonsClosure cl;
\r
6106 /*if (IsIconic(hDlg)) return;*/
\r
6107 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6109 cl.hdwp = BeginDeferWindowPos(8);
\r
6111 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6112 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6113 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6114 if (newTextHeight < 0) {
\r
6115 newSizeY += -newTextHeight;
\r
6116 newTextHeight = 0;
\r
6118 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6119 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6125 cl.newSizeX = newSizeX;
\r
6126 cl.newSizeY = newSizeY;
\r
6127 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6129 EndDeferWindowPos(cl.hdwp);
\r
6132 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6134 RECT rChild, rParent;
\r
6135 int wChild, hChild, wParent, hParent;
\r
6136 int wScreen, hScreen, xNew, yNew;
\r
6139 /* Get the Height and Width of the child window */
\r
6140 GetWindowRect (hwndChild, &rChild);
\r
6141 wChild = rChild.right - rChild.left;
\r
6142 hChild = rChild.bottom - rChild.top;
\r
6144 /* Get the Height and Width of the parent window */
\r
6145 GetWindowRect (hwndParent, &rParent);
\r
6146 wParent = rParent.right - rParent.left;
\r
6147 hParent = rParent.bottom - rParent.top;
\r
6149 /* Get the display limits */
\r
6150 hdc = GetDC (hwndChild);
\r
6151 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6152 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6153 ReleaseDC(hwndChild, hdc);
\r
6155 /* Calculate new X position, then adjust for screen */
\r
6156 xNew = rParent.left + ((wParent - wChild) /2);
\r
6159 } else if ((xNew+wChild) > wScreen) {
\r
6160 xNew = wScreen - wChild;
\r
6163 /* Calculate new Y position, then adjust for screen */
\r
6165 yNew = rParent.top + ((hParent - hChild) /2);
\r
6168 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6173 } else if ((yNew+hChild) > hScreen) {
\r
6174 yNew = hScreen - hChild;
\r
6177 /* Set it, and return */
\r
6178 return SetWindowPos (hwndChild, NULL,
\r
6179 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6182 /* Center one window over another */
\r
6183 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6185 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6188 /*---------------------------------------------------------------------------*\
\r
6190 * Startup Dialog functions
\r
6192 \*---------------------------------------------------------------------------*/
\r
6194 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6196 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6198 while (*cd != NULL) {
\r
6199 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6205 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6207 char buf1[MAX_ARG_LEN];
\r
6210 if (str[0] == '@') {
\r
6211 FILE* f = fopen(str + 1, "r");
\r
6213 DisplayFatalError(str + 1, errno, 2);
\r
6216 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6218 buf1[len] = NULLCHAR;
\r
6222 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6225 char buf[MSG_SIZ];
\r
6226 char *end = strchr(str, '\n');
\r
6227 if (end == NULL) return;
\r
6228 memcpy(buf, str, end - str);
\r
6229 buf[end - str] = NULLCHAR;
\r
6230 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6236 SetStartupDialogEnables(HWND hDlg)
\r
6238 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6239 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6240 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6241 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6242 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6243 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6244 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6245 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6246 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6247 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6248 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6249 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6250 IsDlgButtonChecked(hDlg, OPT_View));
\r
6254 QuoteForFilename(char *filename)
\r
6256 int dquote, space;
\r
6257 dquote = strchr(filename, '"') != NULL;
\r
6258 space = strchr(filename, ' ') != NULL;
\r
6259 if (dquote || space) {
\r
6271 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6273 char buf[MSG_SIZ];
\r
6276 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6277 q = QuoteForFilename(nthcp);
\r
6278 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6279 if (*nthdir != NULLCHAR) {
\r
6280 q = QuoteForFilename(nthdir);
\r
6281 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6283 if (*nthcp == NULLCHAR) {
\r
6284 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6285 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6286 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6287 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6292 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6294 char buf[MSG_SIZ];
\r
6298 switch (message) {
\r
6299 case WM_INITDIALOG:
\r
6300 /* Center the dialog */
\r
6301 CenterWindow (hDlg, GetDesktopWindow());
\r
6302 Translate(hDlg, DLG_Startup);
\r
6303 /* Initialize the dialog items */
\r
6304 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6305 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6306 firstChessProgramNames);
\r
6307 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6308 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6309 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6310 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6311 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6312 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6313 if (*appData.icsHelper != NULLCHAR) {
\r
6314 char *q = QuoteForFilename(appData.icsHelper);
\r
6315 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6317 if (*appData.icsHost == NULLCHAR) {
\r
6318 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6319 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6320 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6321 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6322 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6325 if (appData.icsActive) {
\r
6326 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6328 else if (appData.noChessProgram) {
\r
6329 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6332 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6335 SetStartupDialogEnables(hDlg);
\r
6339 switch (LOWORD(wParam)) {
\r
6341 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6342 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6343 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6345 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6346 ParseArgs(StringGet, &p);
\r
6347 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6348 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6350 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6351 ParseArgs(StringGet, &p);
\r
6352 SwapEngines(singleList); // ... and then make it 'second'
\r
6354 appData.noChessProgram = FALSE;
\r
6355 appData.icsActive = FALSE;
\r
6356 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6357 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6358 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6360 ParseArgs(StringGet, &p);
\r
6361 if (appData.zippyPlay) {
\r
6362 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6363 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6365 ParseArgs(StringGet, &p);
\r
6367 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6368 appData.noChessProgram = TRUE;
\r
6369 appData.icsActive = FALSE;
\r
6371 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6372 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6375 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6376 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6378 ParseArgs(StringGet, &p);
\r
6380 EndDialog(hDlg, TRUE);
\r
6387 case IDM_HELPCONTENTS:
\r
6388 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6389 MessageBox (GetFocus(),
\r
6390 _("Unable to activate help"),
\r
6391 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6396 SetStartupDialogEnables(hDlg);
\r
6404 /*---------------------------------------------------------------------------*\
\r
6406 * About box dialog functions
\r
6408 \*---------------------------------------------------------------------------*/
\r
6410 /* Process messages for "About" dialog box */
\r
6412 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6414 switch (message) {
\r
6415 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6416 /* Center the dialog over the application window */
\r
6417 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6418 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6419 Translate(hDlg, ABOUTBOX);
\r
6423 case WM_COMMAND: /* message: received a command */
\r
6424 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6425 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6426 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6434 /*---------------------------------------------------------------------------*\
\r
6436 * Comment Dialog functions
\r
6438 \*---------------------------------------------------------------------------*/
\r
6441 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6443 static HANDLE hwndText = NULL;
\r
6444 int len, newSizeX, newSizeY;
\r
6445 static int sizeX, sizeY;
\r
6450 switch (message) {
\r
6451 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6452 /* Initialize the dialog items */
\r
6453 Translate(hDlg, DLG_EditComment);
\r
6454 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6455 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6456 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6457 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6458 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6459 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6460 SetWindowText(hDlg, commentTitle);
\r
6461 if (editComment) {
\r
6462 SetFocus(hwndText);
\r
6464 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6466 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6467 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6468 MAKELPARAM(FALSE, 0));
\r
6469 /* Size and position the dialog */
\r
6470 if (!commentDialog) {
\r
6471 commentDialog = hDlg;
\r
6472 GetClientRect(hDlg, &rect);
\r
6473 sizeX = rect.right;
\r
6474 sizeY = rect.bottom;
\r
6475 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6476 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6477 WINDOWPLACEMENT wp;
\r
6478 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6479 wp.length = sizeof(WINDOWPLACEMENT);
\r
6481 wp.showCmd = SW_SHOW;
\r
6482 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6483 wp.rcNormalPosition.left = wpComment.x;
\r
6484 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6485 wp.rcNormalPosition.top = wpComment.y;
\r
6486 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6487 SetWindowPlacement(hDlg, &wp);
\r
6489 GetClientRect(hDlg, &rect);
\r
6490 newSizeX = rect.right;
\r
6491 newSizeY = rect.bottom;
\r
6492 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6493 newSizeX, newSizeY);
\r
6498 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6501 case WM_COMMAND: /* message: received a command */
\r
6502 switch (LOWORD(wParam)) {
\r
6504 if (editComment) {
\r
6506 /* Read changed options from the dialog box */
\r
6507 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6508 len = GetWindowTextLength(hwndText);
\r
6509 str = (char *) malloc(len + 1);
\r
6510 GetWindowText(hwndText, str, len + 1);
\r
6519 ReplaceComment(commentIndex, str);
\r
6526 case OPT_CancelComment:
\r
6530 case OPT_ClearComment:
\r
6531 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6534 case OPT_EditComment:
\r
6535 EditCommentEvent();
\r
6543 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6544 if( wParam == OPT_CommentText ) {
\r
6545 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6547 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6548 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6552 pt.x = LOWORD( lpMF->lParam );
\r
6553 pt.y = HIWORD( lpMF->lParam );
\r
6555 if(lpMF->msg == WM_CHAR) {
\r
6557 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6558 index = sel.cpMin;
\r
6560 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6562 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6563 len = GetWindowTextLength(hwndText);
\r
6564 str = (char *) malloc(len + 1);
\r
6565 GetWindowText(hwndText, str, len + 1);
\r
6566 ReplaceComment(commentIndex, str);
\r
6567 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6568 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6571 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6572 lpMF->msg = WM_USER;
\r
6580 newSizeX = LOWORD(lParam);
\r
6581 newSizeY = HIWORD(lParam);
\r
6582 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6587 case WM_GETMINMAXINFO:
\r
6588 /* Prevent resizing window too small */
\r
6589 mmi = (MINMAXINFO *) lParam;
\r
6590 mmi->ptMinTrackSize.x = 100;
\r
6591 mmi->ptMinTrackSize.y = 100;
\r
6598 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6603 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6605 if (str == NULL) str = "";
\r
6606 p = (char *) malloc(2 * strlen(str) + 2);
\r
6609 if (*str == '\n') *q++ = '\r';
\r
6613 if (commentText != NULL) free(commentText);
\r
6615 commentIndex = index;
\r
6616 commentTitle = title;
\r
6618 editComment = edit;
\r
6620 if (commentDialog) {
\r
6621 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6622 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6624 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6625 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6626 hwndMain, (DLGPROC)lpProc);
\r
6627 FreeProcInstance(lpProc);
\r
6633 /*---------------------------------------------------------------------------*\
\r
6635 * Type-in move dialog functions
\r
6637 \*---------------------------------------------------------------------------*/
\r
6640 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6642 char move[MSG_SIZ];
\r
6645 switch (message) {
\r
6646 case WM_INITDIALOG:
\r
6647 move[0] = (char) lParam;
\r
6648 move[1] = NULLCHAR;
\r
6649 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6650 Translate(hDlg, DLG_TypeInMove);
\r
6651 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6652 SetWindowText(hInput, move);
\r
6654 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6658 switch (LOWORD(wParam)) {
\r
6661 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6662 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6663 TypeInDoneEvent(move);
\r
6664 EndDialog(hDlg, TRUE);
\r
6667 EndDialog(hDlg, FALSE);
\r
6678 PopUpMoveDialog(char firstchar)
\r
6682 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6683 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6684 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6685 FreeProcInstance(lpProc);
\r
6688 /*---------------------------------------------------------------------------*\
\r
6690 * Type-in name dialog functions
\r
6692 \*---------------------------------------------------------------------------*/
\r
6695 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6697 char move[MSG_SIZ];
\r
6700 switch (message) {
\r
6701 case WM_INITDIALOG:
\r
6702 move[0] = (char) lParam;
\r
6703 move[1] = NULLCHAR;
\r
6704 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6705 Translate(hDlg, DLG_TypeInName);
\r
6706 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6707 SetWindowText(hInput, move);
\r
6709 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6713 switch (LOWORD(wParam)) {
\r
6715 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6716 appData.userName = strdup(move);
\r
6719 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6720 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6721 DisplayTitle(move);
\r
6725 EndDialog(hDlg, TRUE);
\r
6728 EndDialog(hDlg, FALSE);
\r
6739 PopUpNameDialog(char firstchar)
\r
6743 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6744 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6745 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6746 FreeProcInstance(lpProc);
\r
6749 /*---------------------------------------------------------------------------*\
\r
6753 \*---------------------------------------------------------------------------*/
\r
6755 /* Nonmodal error box */
\r
6756 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6757 WPARAM wParam, LPARAM lParam);
\r
6760 ErrorPopUp(char *title, char *content)
\r
6764 BOOLEAN modal = hwndMain == NULL;
\r
6782 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6783 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6786 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6788 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6789 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6790 hwndMain, (DLGPROC)lpProc);
\r
6791 FreeProcInstance(lpProc);
\r
6798 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6799 if (errorDialog == NULL) return;
\r
6800 DestroyWindow(errorDialog);
\r
6801 errorDialog = NULL;
\r
6802 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6806 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6810 switch (message) {
\r
6811 case WM_INITDIALOG:
\r
6812 GetWindowRect(hDlg, &rChild);
\r
6815 SetWindowPos(hDlg, NULL, rChild.left,
\r
6816 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6817 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6821 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6822 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6823 and it doesn't work when you resize the dialog.
\r
6824 For now, just give it a default position.
\r
6826 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6827 Translate(hDlg, DLG_Error);
\r
6829 errorDialog = hDlg;
\r
6830 SetWindowText(hDlg, errorTitle);
\r
6831 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6835 switch (LOWORD(wParam)) {
\r
6838 if (errorDialog == hDlg) errorDialog = NULL;
\r
6839 DestroyWindow(hDlg);
\r
6851 HWND gothicDialog = NULL;
\r
6854 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6857 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6859 switch (message) {
\r
6860 case WM_INITDIALOG:
\r
6861 GetWindowRect(hDlg, &rChild);
\r
6863 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6867 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6868 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6869 and it doesn't work when you resize the dialog.
\r
6870 For now, just give it a default position.
\r
6872 gothicDialog = hDlg;
\r
6873 SetWindowText(hDlg, errorTitle);
\r
6874 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6878 switch (LOWORD(wParam)) {
\r
6881 if (errorDialog == hDlg) errorDialog = NULL;
\r
6882 DestroyWindow(hDlg);
\r
6894 GothicPopUp(char *title, VariantClass variant)
\r
6897 static char *lastTitle;
\r
6899 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6900 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6902 if(lastTitle != title && gothicDialog != NULL) {
\r
6903 DestroyWindow(gothicDialog);
\r
6904 gothicDialog = NULL;
\r
6906 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6907 title = lastTitle;
\r
6908 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6909 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6910 hwndMain, (DLGPROC)lpProc);
\r
6911 FreeProcInstance(lpProc);
\r
6916 /*---------------------------------------------------------------------------*\
\r
6918 * Ics Interaction console functions
\r
6920 \*---------------------------------------------------------------------------*/
\r
6922 #define HISTORY_SIZE 64
\r
6923 static char *history[HISTORY_SIZE];
\r
6924 int histIn = 0, histP = 0;
\r
6928 SaveInHistory(char *cmd)
\r
6930 if (history[histIn] != NULL) {
\r
6931 free(history[histIn]);
\r
6932 history[histIn] = NULL;
\r
6934 if (*cmd == NULLCHAR) return;
\r
6935 history[histIn] = StrSave(cmd);
\r
6936 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6937 if (history[histIn] != NULL) {
\r
6938 free(history[histIn]);
\r
6940 history[histIn] = NULL;
\r
6946 PrevInHistory(char *cmd)
\r
6949 if (histP == histIn) {
\r
6950 if (history[histIn] != NULL) free(history[histIn]);
\r
6951 history[histIn] = StrSave(cmd);
\r
6953 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6954 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6956 return history[histP];
\r
6962 if (histP == histIn) return NULL;
\r
6963 histP = (histP + 1) % HISTORY_SIZE;
\r
6964 return history[histP];
\r
6968 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6972 hmenu = LoadMenu(hInst, "TextMenu");
\r
6973 h = GetSubMenu(hmenu, 0);
\r
6975 if (strcmp(e->item, "-") == 0) {
\r
6976 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6977 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6978 int flags = MF_STRING, j = 0;
\r
6979 if (e->item[0] == '|') {
\r
6980 flags |= MF_MENUBARBREAK;
\r
6983 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6984 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
6992 WNDPROC consoleTextWindowProc;
\r
6995 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6997 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6998 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7002 SetWindowText(hInput, command);
\r
7004 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7006 sel.cpMin = 999999;
\r
7007 sel.cpMax = 999999;
\r
7008 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7013 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7014 if (sel.cpMin == sel.cpMax) {
\r
7015 /* Expand to surrounding word */
\r
7018 tr.chrg.cpMax = sel.cpMin;
\r
7019 tr.chrg.cpMin = --sel.cpMin;
\r
7020 if (sel.cpMin < 0) break;
\r
7021 tr.lpstrText = name;
\r
7022 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7023 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7027 tr.chrg.cpMin = sel.cpMax;
\r
7028 tr.chrg.cpMax = ++sel.cpMax;
\r
7029 tr.lpstrText = name;
\r
7030 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7031 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7034 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7035 MessageBeep(MB_ICONEXCLAMATION);
\r
7039 tr.lpstrText = name;
\r
7040 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7042 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7043 MessageBeep(MB_ICONEXCLAMATION);
\r
7046 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7049 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7050 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7051 SetWindowText(hInput, buf);
\r
7052 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7054 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7055 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7056 SetWindowText(hInput, buf);
\r
7057 sel.cpMin = 999999;
\r
7058 sel.cpMax = 999999;
\r
7059 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7065 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7070 switch (message) {
\r
7072 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7073 if(wParam=='R') return 0;
\r
7076 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7079 sel.cpMin = 999999;
\r
7080 sel.cpMax = 999999;
\r
7081 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7082 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7087 if(wParam != '\022') {
\r
7088 if (wParam == '\t') {
\r
7089 if (GetKeyState(VK_SHIFT) < 0) {
\r
7091 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7092 if (buttonDesc[0].hwnd) {
\r
7093 SetFocus(buttonDesc[0].hwnd);
\r
7095 SetFocus(hwndMain);
\r
7099 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7102 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7103 JAWS_DELETE( SetFocus(hInput); )
\r
7104 SendMessage(hInput, message, wParam, lParam);
\r
7107 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7109 case WM_RBUTTONDOWN:
\r
7110 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7111 /* Move selection here if it was empty */
\r
7113 pt.x = LOWORD(lParam);
\r
7114 pt.y = HIWORD(lParam);
\r
7115 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7116 if (sel.cpMin == sel.cpMax) {
\r
7117 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7118 sel.cpMax = sel.cpMin;
\r
7119 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7121 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7122 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7124 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7125 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7126 if (sel.cpMin == sel.cpMax) {
\r
7127 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7128 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7130 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7131 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7133 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7134 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7135 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7136 MenuPopup(hwnd, pt, hmenu, -1);
\r
7140 case WM_RBUTTONUP:
\r
7141 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7142 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7143 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7147 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7149 return SendMessage(hInput, message, wParam, lParam);
\r
7150 case WM_MBUTTONDOWN:
\r
7151 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7153 switch (LOWORD(wParam)) {
\r
7154 case IDM_QuickPaste:
\r
7156 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7157 if (sel.cpMin == sel.cpMax) {
\r
7158 MessageBeep(MB_ICONEXCLAMATION);
\r
7161 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7162 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7163 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7168 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7171 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7174 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7178 int i = LOWORD(wParam) - IDM_CommandX;
\r
7179 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7180 icsTextMenuEntry[i].command != NULL) {
\r
7181 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7182 icsTextMenuEntry[i].getname,
\r
7183 icsTextMenuEntry[i].immediate);
\r
7191 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7194 WNDPROC consoleInputWindowProc;
\r
7197 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7199 char buf[MSG_SIZ];
\r
7201 static BOOL sendNextChar = FALSE;
\r
7202 static BOOL quoteNextChar = FALSE;
\r
7203 InputSource *is = consoleInputSource;
\r
7207 switch (message) {
\r
7209 if (!appData.localLineEditing || sendNextChar) {
\r
7210 is->buf[0] = (CHAR) wParam;
\r
7212 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7213 sendNextChar = FALSE;
\r
7216 if (quoteNextChar) {
\r
7217 buf[0] = (char) wParam;
\r
7218 buf[1] = NULLCHAR;
\r
7219 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7220 quoteNextChar = FALSE;
\r
7224 case '\r': /* Enter key */
\r
7225 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7226 if (consoleEcho) SaveInHistory(is->buf);
\r
7227 is->buf[is->count++] = '\n';
\r
7228 is->buf[is->count] = NULLCHAR;
\r
7229 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7230 if (consoleEcho) {
\r
7231 ConsoleOutput(is->buf, is->count, TRUE);
\r
7232 } else if (appData.localLineEditing) {
\r
7233 ConsoleOutput("\n", 1, TRUE);
\r
7236 case '\033': /* Escape key */
\r
7237 SetWindowText(hwnd, "");
\r
7238 cf.cbSize = sizeof(CHARFORMAT);
\r
7239 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7240 if (consoleEcho) {
\r
7241 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7243 cf.crTextColor = COLOR_ECHOOFF;
\r
7245 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7246 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7248 case '\t': /* Tab key */
\r
7249 if (GetKeyState(VK_SHIFT) < 0) {
\r
7251 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7254 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7255 if (buttonDesc[0].hwnd) {
\r
7256 SetFocus(buttonDesc[0].hwnd);
\r
7258 SetFocus(hwndMain);
\r
7262 case '\023': /* Ctrl+S */
\r
7263 sendNextChar = TRUE;
\r
7265 case '\021': /* Ctrl+Q */
\r
7266 quoteNextChar = TRUE;
\r
7276 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7277 p = PrevInHistory(buf);
\r
7279 SetWindowText(hwnd, p);
\r
7280 sel.cpMin = 999999;
\r
7281 sel.cpMax = 999999;
\r
7282 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7287 p = NextInHistory();
\r
7289 SetWindowText(hwnd, p);
\r
7290 sel.cpMin = 999999;
\r
7291 sel.cpMax = 999999;
\r
7292 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7298 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7302 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7306 case WM_MBUTTONDOWN:
\r
7307 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7308 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7310 case WM_RBUTTONUP:
\r
7311 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7312 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7313 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7317 hmenu = LoadMenu(hInst, "InputMenu");
\r
7318 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7319 if (sel.cpMin == sel.cpMax) {
\r
7320 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7321 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7323 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7324 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7326 pt.x = LOWORD(lParam);
\r
7327 pt.y = HIWORD(lParam);
\r
7328 MenuPopup(hwnd, pt, hmenu, -1);
\r
7332 switch (LOWORD(wParam)) {
\r
7334 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7336 case IDM_SelectAll:
\r
7338 sel.cpMax = -1; /*999999?*/
\r
7339 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7342 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7345 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7348 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7353 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7356 #define CO_MAX 100000
\r
7357 #define CO_TRIM 1000
\r
7360 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7362 static SnapData sd;
\r
7363 HWND hText, hInput;
\r
7365 static int sizeX, sizeY;
\r
7366 int newSizeX, newSizeY;
\r
7370 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7371 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7373 switch (message) {
\r
7375 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7377 ENLINK *pLink = (ENLINK*)lParam;
\r
7378 if (pLink->msg == WM_LBUTTONUP)
\r
7382 tr.chrg = pLink->chrg;
\r
7383 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7384 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7385 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7386 free(tr.lpstrText);
\r
7390 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7391 hwndConsole = hDlg;
\r
7393 consoleTextWindowProc = (WNDPROC)
\r
7394 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7395 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7396 consoleInputWindowProc = (WNDPROC)
\r
7397 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7398 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7399 Colorize(ColorNormal, TRUE);
\r
7400 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7401 ChangedConsoleFont();
\r
7402 GetClientRect(hDlg, &rect);
\r
7403 sizeX = rect.right;
\r
7404 sizeY = rect.bottom;
\r
7405 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7406 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7407 WINDOWPLACEMENT wp;
\r
7408 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7409 wp.length = sizeof(WINDOWPLACEMENT);
\r
7411 wp.showCmd = SW_SHOW;
\r
7412 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7413 wp.rcNormalPosition.left = wpConsole.x;
\r
7414 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7415 wp.rcNormalPosition.top = wpConsole.y;
\r
7416 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7417 SetWindowPlacement(hDlg, &wp);
\r
7420 // [HGM] Chessknight's change 2004-07-13
\r
7421 else { /* Determine Defaults */
\r
7422 WINDOWPLACEMENT wp;
\r
7423 wpConsole.x = wpMain.width + 1;
\r
7424 wpConsole.y = wpMain.y;
\r
7425 wpConsole.width = screenWidth - wpMain.width;
\r
7426 wpConsole.height = wpMain.height;
\r
7427 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7428 wp.length = sizeof(WINDOWPLACEMENT);
\r
7430 wp.showCmd = SW_SHOW;
\r
7431 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7432 wp.rcNormalPosition.left = wpConsole.x;
\r
7433 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7434 wp.rcNormalPosition.top = wpConsole.y;
\r
7435 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7436 SetWindowPlacement(hDlg, &wp);
\r
7439 // Allow hText to highlight URLs and send notifications on them
\r
7440 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7441 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7442 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7443 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7457 if (IsIconic(hDlg)) break;
\r
7458 newSizeX = LOWORD(lParam);
\r
7459 newSizeY = HIWORD(lParam);
\r
7460 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7461 RECT rectText, rectInput;
\r
7463 int newTextHeight, newTextWidth;
\r
7464 GetWindowRect(hText, &rectText);
\r
7465 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7466 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7467 if (newTextHeight < 0) {
\r
7468 newSizeY += -newTextHeight;
\r
7469 newTextHeight = 0;
\r
7471 SetWindowPos(hText, NULL, 0, 0,
\r
7472 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7473 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7474 pt.x = rectInput.left;
\r
7475 pt.y = rectInput.top + newSizeY - sizeY;
\r
7476 ScreenToClient(hDlg, &pt);
\r
7477 SetWindowPos(hInput, NULL,
\r
7478 pt.x, pt.y, /* needs client coords */
\r
7479 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7480 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7486 case WM_GETMINMAXINFO:
\r
7487 /* Prevent resizing window too small */
\r
7488 mmi = (MINMAXINFO *) lParam;
\r
7489 mmi->ptMinTrackSize.x = 100;
\r
7490 mmi->ptMinTrackSize.y = 100;
\r
7493 /* [AS] Snapping */
\r
7494 case WM_ENTERSIZEMOVE:
\r
7495 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7498 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7501 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7503 case WM_EXITSIZEMOVE:
\r
7504 UpdateICSWidth(hText);
\r
7505 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7508 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7516 if (hwndConsole) return;
\r
7517 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7518 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7523 ConsoleOutput(char* data, int length, int forceVisible)
\r
7528 char buf[CO_MAX+1];
\r
7531 static int delayLF = 0;
\r
7532 CHARRANGE savesel, sel;
\r
7534 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7542 while (length--) {
\r
7550 } else if (*p == '\007') {
\r
7551 MyPlaySound(&sounds[(int)SoundBell]);
\r
7558 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7559 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7560 /* Save current selection */
\r
7561 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7562 exlen = GetWindowTextLength(hText);
\r
7563 /* Find out whether current end of text is visible */
\r
7564 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7565 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7566 /* Trim existing text if it's too long */
\r
7567 if (exlen + (q - buf) > CO_MAX) {
\r
7568 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7571 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7572 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7574 savesel.cpMin -= trim;
\r
7575 savesel.cpMax -= trim;
\r
7576 if (exlen < 0) exlen = 0;
\r
7577 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7578 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7580 /* Append the new text */
\r
7581 sel.cpMin = exlen;
\r
7582 sel.cpMax = exlen;
\r
7583 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7584 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7585 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7586 if (forceVisible || exlen == 0 ||
\r
7587 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7588 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7589 /* Scroll to make new end of text visible if old end of text
\r
7590 was visible or new text is an echo of user typein */
\r
7591 sel.cpMin = 9999999;
\r
7592 sel.cpMax = 9999999;
\r
7593 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7594 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7595 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7596 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7598 if (savesel.cpMax == exlen || forceVisible) {
\r
7599 /* Move insert point to new end of text if it was at the old
\r
7600 end of text or if the new text is an echo of user typein */
\r
7601 sel.cpMin = 9999999;
\r
7602 sel.cpMax = 9999999;
\r
7603 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7605 /* Restore previous selection */
\r
7606 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7608 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7615 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7619 COLORREF oldFg, oldBg;
\r
7623 if(copyNumber > 1)
\r
7624 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7626 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7627 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7628 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7631 rect.right = x + squareSize;
\r
7633 rect.bottom = y + squareSize;
\r
7636 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7637 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7638 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7639 &rect, str, strlen(str), NULL);
\r
7641 (void) SetTextColor(hdc, oldFg);
\r
7642 (void) SetBkColor(hdc, oldBg);
\r
7643 (void) SelectObject(hdc, oldFont);
\r
7647 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7648 RECT *rect, char *color, char *flagFell)
\r
7652 COLORREF oldFg, oldBg;
\r
7655 if (twoBoards && partnerUp) return;
\r
7656 if (appData.clockMode) {
\r
7657 if (tinyLayout == 2)
\r
7658 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7660 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7667 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7668 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7670 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7671 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7673 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7677 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7678 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7679 rect, str, strlen(str), NULL);
\r
7680 if(logoHeight > 0 && appData.clockMode) {
\r
7682 str += strlen(color)+2;
\r
7683 r.top = rect->top + logoHeight/2;
\r
7684 r.left = rect->left;
\r
7685 r.right = rect->right;
\r
7686 r.bottom = rect->bottom;
\r
7687 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7688 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7689 &r, str, strlen(str), NULL);
\r
7691 (void) SetTextColor(hdc, oldFg);
\r
7692 (void) SetBkColor(hdc, oldBg);
\r
7693 (void) SelectObject(hdc, oldFont);
\r
7698 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7704 if( count <= 0 ) {
\r
7705 if (appData.debugMode) {
\r
7706 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7709 return ERROR_INVALID_USER_BUFFER;
\r
7712 ResetEvent(ovl->hEvent);
\r
7713 ovl->Offset = ovl->OffsetHigh = 0;
\r
7714 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7718 err = GetLastError();
\r
7719 if (err == ERROR_IO_PENDING) {
\r
7720 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7724 err = GetLastError();
\r
7731 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7736 ResetEvent(ovl->hEvent);
\r
7737 ovl->Offset = ovl->OffsetHigh = 0;
\r
7738 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7742 err = GetLastError();
\r
7743 if (err == ERROR_IO_PENDING) {
\r
7744 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7748 err = GetLastError();
\r
7755 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7756 void CheckForInputBufferFull( InputSource * is )
\r
7758 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7759 /* Look for end of line */
\r
7760 char * p = is->buf;
\r
7762 while( p < is->next && *p != '\n' ) {
\r
7766 if( p >= is->next ) {
\r
7767 if (appData.debugMode) {
\r
7768 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7771 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7772 is->count = (DWORD) -1;
\r
7773 is->next = is->buf;
\r
7779 InputThread(LPVOID arg)
\r
7784 is = (InputSource *) arg;
\r
7785 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7786 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7787 while (is->hThread != NULL) {
\r
7788 is->error = DoReadFile(is->hFile, is->next,
\r
7789 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7790 &is->count, &ovl);
\r
7791 if (is->error == NO_ERROR) {
\r
7792 is->next += is->count;
\r
7794 if (is->error == ERROR_BROKEN_PIPE) {
\r
7795 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7798 is->count = (DWORD) -1;
\r
7799 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7804 CheckForInputBufferFull( is );
\r
7806 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7808 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7810 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7813 CloseHandle(ovl.hEvent);
\r
7814 CloseHandle(is->hFile);
\r
7816 if (appData.debugMode) {
\r
7817 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7824 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7826 NonOvlInputThread(LPVOID arg)
\r
7833 is = (InputSource *) arg;
\r
7834 while (is->hThread != NULL) {
\r
7835 is->error = ReadFile(is->hFile, is->next,
\r
7836 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7837 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7838 if (is->error == NO_ERROR) {
\r
7839 /* Change CRLF to LF */
\r
7840 if (is->next > is->buf) {
\r
7842 i = is->count + 1;
\r
7850 if (prev == '\r' && *p == '\n') {
\r
7862 if (is->error == ERROR_BROKEN_PIPE) {
\r
7863 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7866 is->count = (DWORD) -1;
\r
7870 CheckForInputBufferFull( is );
\r
7872 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7874 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7876 if (is->count < 0) break; /* Quit on error */
\r
7878 CloseHandle(is->hFile);
\r
7883 SocketInputThread(LPVOID arg)
\r
7887 is = (InputSource *) arg;
\r
7888 while (is->hThread != NULL) {
\r
7889 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7890 if ((int)is->count == SOCKET_ERROR) {
\r
7891 is->count = (DWORD) -1;
\r
7892 is->error = WSAGetLastError();
\r
7894 is->error = NO_ERROR;
\r
7895 is->next += is->count;
\r
7896 if (is->count == 0 && is->second == is) {
\r
7897 /* End of file on stderr; quit with no message */
\r
7901 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7903 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7905 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7911 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7915 is = (InputSource *) lParam;
\r
7916 if (is->lineByLine) {
\r
7917 /* Feed in lines one by one */
\r
7918 char *p = is->buf;
\r
7920 while (q < is->next) {
\r
7921 if (*q++ == '\n') {
\r
7922 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7927 /* Move any partial line to the start of the buffer */
\r
7929 while (p < is->next) {
\r
7934 if (is->error != NO_ERROR || is->count == 0) {
\r
7935 /* Notify backend of the error. Note: If there was a partial
\r
7936 line at the end, it is not flushed through. */
\r
7937 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7940 /* Feed in the whole chunk of input at once */
\r
7941 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7942 is->next = is->buf;
\r
7946 /*---------------------------------------------------------------------------*\
\r
7948 * Menu enables. Used when setting various modes.
\r
7950 \*---------------------------------------------------------------------------*/
\r
7958 GreyRevert(Boolean grey)
\r
7959 { // [HGM] vari: for retracting variations in local mode
\r
7960 HMENU hmenu = GetMenu(hwndMain);
\r
7961 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7962 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7966 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7968 while (enab->item > 0) {
\r
7969 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7974 Enables gnuEnables[] = {
\r
7975 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7980 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7981 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7982 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7983 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7984 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7985 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7986 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
7987 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
7989 // Needed to switch from ncp to GNU mode on Engine Load
\r
7990 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7991 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7992 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7993 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7994 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
7995 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
7996 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
7997 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
8000 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8001 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8002 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8003 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8007 Enables icsEnables[] = {
\r
8008 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8016 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8020 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8024 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8025 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8026 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8027 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8032 Enables zippyEnables[] = {
\r
8033 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8034 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8041 Enables ncpEnables[] = {
\r
8042 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8043 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8044 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8045 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8046 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8047 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8052 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8055 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8056 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8067 Enables trainingOnEnables[] = {
\r
8068 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8075 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8076 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8080 Enables trainingOffEnables[] = {
\r
8081 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8082 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8083 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8084 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8085 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8086 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8087 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8088 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8089 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8093 /* These modify either ncpEnables or gnuEnables */
\r
8094 Enables cmailEnables[] = {
\r
8095 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8096 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8097 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8098 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8099 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8100 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8101 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8105 Enables machineThinkingEnables[] = {
\r
8106 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8114 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8115 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8116 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8117 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8118 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8119 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8120 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8121 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8125 Enables userThinkingEnables[] = {
\r
8126 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8133 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8134 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8135 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8136 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8137 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8138 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8139 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8140 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8141 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8145 /*---------------------------------------------------------------------------*\
\r
8147 * Front-end interface functions exported by XBoard.
\r
8148 * Functions appear in same order as prototypes in frontend.h.
\r
8150 \*---------------------------------------------------------------------------*/
\r
8152 CheckMark(UINT item, int state)
\r
8154 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8160 static UINT prevChecked = 0;
\r
8161 static int prevPausing = 0;
\r
8164 if (pausing != prevPausing) {
\r
8165 prevPausing = pausing;
\r
8166 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8167 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8168 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8171 switch (gameMode) {
\r
8172 case BeginningOfGame:
\r
8173 if (appData.icsActive)
\r
8174 nowChecked = IDM_IcsClient;
\r
8175 else if (appData.noChessProgram)
\r
8176 nowChecked = IDM_EditGame;
\r
8178 nowChecked = IDM_MachineBlack;
\r
8180 case MachinePlaysBlack:
\r
8181 nowChecked = IDM_MachineBlack;
\r
8183 case MachinePlaysWhite:
\r
8184 nowChecked = IDM_MachineWhite;
\r
8186 case TwoMachinesPlay:
\r
8187 nowChecked = IDM_TwoMachines;
\r
8190 nowChecked = IDM_AnalysisMode;
\r
8193 nowChecked = IDM_AnalyzeFile;
\r
8196 nowChecked = IDM_EditGame;
\r
8198 case PlayFromGameFile:
\r
8199 nowChecked = IDM_LoadGame;
\r
8201 case EditPosition:
\r
8202 nowChecked = IDM_EditPosition;
\r
8205 nowChecked = IDM_Training;
\r
8207 case IcsPlayingWhite:
\r
8208 case IcsPlayingBlack:
\r
8209 case IcsObserving:
\r
8211 nowChecked = IDM_IcsClient;
\r
8218 CheckMark(prevChecked, MF_UNCHECKED);
\r
8219 CheckMark(nowChecked, MF_CHECKED);
\r
8220 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8222 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8223 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8224 MF_BYCOMMAND|MF_ENABLED);
\r
8226 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8227 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8230 prevChecked = nowChecked;
\r
8232 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8233 if (appData.icsActive) {
\r
8234 if (appData.icsEngineAnalyze) {
\r
8235 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8237 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8240 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8246 HMENU hmenu = GetMenu(hwndMain);
\r
8247 SetMenuEnables(hmenu, icsEnables);
\r
8248 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8249 MF_BYCOMMAND|MF_ENABLED);
\r
8251 if (appData.zippyPlay) {
\r
8252 SetMenuEnables(hmenu, zippyEnables);
\r
8253 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8254 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8255 MF_BYCOMMAND|MF_ENABLED);
\r
8263 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8269 HMENU hmenu = GetMenu(hwndMain);
\r
8270 SetMenuEnables(hmenu, ncpEnables);
\r
8271 DrawMenuBar(hwndMain);
\r
8277 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8281 SetTrainingModeOn()
\r
8284 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8285 for (i = 0; i < N_BUTTONS; i++) {
\r
8286 if (buttonDesc[i].hwnd != NULL)
\r
8287 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8292 VOID SetTrainingModeOff()
\r
8295 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8296 for (i = 0; i < N_BUTTONS; i++) {
\r
8297 if (buttonDesc[i].hwnd != NULL)
\r
8298 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8304 SetUserThinkingEnables()
\r
8306 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8310 SetMachineThinkingEnables()
\r
8312 HMENU hMenu = GetMenu(hwndMain);
\r
8313 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8315 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8317 if (gameMode == MachinePlaysBlack) {
\r
8318 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8319 } else if (gameMode == MachinePlaysWhite) {
\r
8320 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8321 } else if (gameMode == TwoMachinesPlay) {
\r
8322 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8328 DisplayTitle(char *str)
\r
8330 char title[MSG_SIZ], *host;
\r
8331 if (str[0] != NULLCHAR) {
\r
8332 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8333 } else if (appData.icsActive) {
\r
8334 if (appData.icsCommPort[0] != NULLCHAR)
\r
8337 host = appData.icsHost;
\r
8338 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8339 } else if (appData.noChessProgram) {
\r
8340 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8342 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8343 strcat(title, ": ");
\r
8344 strcat(title, first.tidy);
\r
8346 SetWindowText(hwndMain, title);
\r
8351 DisplayMessage(char *str1, char *str2)
\r
8355 int remain = MESSAGE_TEXT_MAX - 1;
\r
8358 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8359 messageText[0] = NULLCHAR;
\r
8361 len = strlen(str1);
\r
8362 if (len > remain) len = remain;
\r
8363 strncpy(messageText, str1, len);
\r
8364 messageText[len] = NULLCHAR;
\r
8367 if (*str2 && remain >= 2) {
\r
8369 strcat(messageText, " ");
\r
8372 len = strlen(str2);
\r
8373 if (len > remain) len = remain;
\r
8374 strncat(messageText, str2, len);
\r
8376 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8377 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8379 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8383 hdc = GetDC(hwndMain);
\r
8384 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8385 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8386 &messageRect, messageText, strlen(messageText), NULL);
\r
8387 (void) SelectObject(hdc, oldFont);
\r
8388 (void) ReleaseDC(hwndMain, hdc);
\r
8392 DisplayError(char *str, int error)
\r
8394 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8398 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8400 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8401 NULL, error, LANG_NEUTRAL,
\r
8402 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8404 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8406 ErrorMap *em = errmap;
\r
8407 while (em->err != 0 && em->err != error) em++;
\r
8408 if (em->err != 0) {
\r
8409 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8411 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8416 ErrorPopUp(_("Error"), buf);
\r
8421 DisplayMoveError(char *str)
\r
8423 fromX = fromY = -1;
\r
8424 ClearHighlights();
\r
8425 DrawPosition(FALSE, NULL);
\r
8426 if (appData.popupMoveErrors) {
\r
8427 ErrorPopUp(_("Error"), str);
\r
8429 DisplayMessage(str, "");
\r
8430 moveErrorMessageUp = TRUE;
\r
8435 DisplayFatalError(char *str, int error, int exitStatus)
\r
8437 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8439 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8442 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8443 NULL, error, LANG_NEUTRAL,
\r
8444 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8446 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8448 ErrorMap *em = errmap;
\r
8449 while (em->err != 0 && em->err != error) em++;
\r
8450 if (em->err != 0) {
\r
8451 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8453 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8458 if (appData.debugMode) {
\r
8459 fprintf(debugFP, "%s: %s\n", label, str);
\r
8461 if (appData.popupExitMessage) {
\r
8462 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8463 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8465 ExitEvent(exitStatus);
\r
8470 DisplayInformation(char *str)
\r
8472 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8477 DisplayNote(char *str)
\r
8479 ErrorPopUp(_("Note"), str);
\r
8484 char *title, *question, *replyPrefix;
\r
8489 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8491 static QuestionParams *qp;
\r
8492 char reply[MSG_SIZ];
\r
8495 switch (message) {
\r
8496 case WM_INITDIALOG:
\r
8497 qp = (QuestionParams *) lParam;
\r
8498 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8499 Translate(hDlg, DLG_Question);
\r
8500 SetWindowText(hDlg, qp->title);
\r
8501 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8502 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8506 switch (LOWORD(wParam)) {
\r
8508 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8509 if (*reply) strcat(reply, " ");
\r
8510 len = strlen(reply);
\r
8511 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8512 strcat(reply, "\n");
\r
8513 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8514 EndDialog(hDlg, TRUE);
\r
8515 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8518 EndDialog(hDlg, FALSE);
\r
8529 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8531 QuestionParams qp;
\r
8535 qp.question = question;
\r
8536 qp.replyPrefix = replyPrefix;
\r
8538 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8539 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8540 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8541 FreeProcInstance(lpProc);
\r
8544 /* [AS] Pick FRC position */
\r
8545 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8547 static int * lpIndexFRC;
\r
8553 case WM_INITDIALOG:
\r
8554 lpIndexFRC = (int *) lParam;
\r
8556 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8557 Translate(hDlg, DLG_NewGameFRC);
\r
8559 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8560 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8561 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8562 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8567 switch( LOWORD(wParam) ) {
\r
8569 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8570 EndDialog( hDlg, 0 );
\r
8571 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8574 EndDialog( hDlg, 1 );
\r
8576 case IDC_NFG_Edit:
\r
8577 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8578 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8580 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8583 case IDC_NFG_Random:
\r
8584 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8585 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8598 int index = appData.defaultFrcPosition;
\r
8599 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8601 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8603 if( result == 0 ) {
\r
8604 appData.defaultFrcPosition = index;
\r
8610 /* [AS] Game list options. Refactored by HGM */
\r
8612 HWND gameListOptionsDialog;
\r
8614 // low-level front-end: clear text edit / list widget
\r
8619 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8622 // low-level front-end: clear text edit / list widget
\r
8624 GLT_DeSelectList()
\r
8626 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8629 // low-level front-end: append line to text edit / list widget
\r
8631 GLT_AddToList( char *name )
\r
8634 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8638 // low-level front-end: get line from text edit / list widget
\r
8640 GLT_GetFromList( int index, char *name )
\r
8643 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8649 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8651 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8652 int idx2 = idx1 + delta;
\r
8653 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8655 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8658 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8659 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8660 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8661 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8665 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8669 case WM_INITDIALOG:
\r
8670 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8672 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8673 Translate(hDlg, DLG_GameListOptions);
\r
8675 /* Initialize list */
\r
8676 GLT_TagsToList( lpUserGLT );
\r
8678 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8683 switch( LOWORD(wParam) ) {
\r
8686 EndDialog( hDlg, 0 );
\r
8689 EndDialog( hDlg, 1 );
\r
8692 case IDC_GLT_Default:
\r
8693 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8696 case IDC_GLT_Restore:
\r
8697 GLT_TagsToList( appData.gameListTags );
\r
8701 GLT_MoveSelection( hDlg, -1 );
\r
8704 case IDC_GLT_Down:
\r
8705 GLT_MoveSelection( hDlg, +1 );
\r
8715 int GameListOptions()
\r
8718 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8720 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8722 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8724 if( result == 0 ) {
\r
8725 char *oldTags = appData.gameListTags;
\r
8726 /* [AS] Memory leak here! */
\r
8727 appData.gameListTags = strdup( lpUserGLT );
\r
8728 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8729 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8736 DisplayIcsInteractionTitle(char *str)
\r
8738 char consoleTitle[MSG_SIZ];
\r
8740 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8741 SetWindowText(hwndConsole, consoleTitle);
\r
8743 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8744 char buf[MSG_SIZ], *p = buf, *q;
\r
8745 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8747 q = strchr(p, ';');
\r
8749 if(*p) ChatPopUp(p);
\r
8753 SetActiveWindow(hwndMain);
\r
8757 DrawPosition(int fullRedraw, Board board)
\r
8759 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8762 void NotifyFrontendLogin()
\r
8765 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8771 fromX = fromY = -1;
\r
8772 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8773 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8774 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8775 dragInfo.lastpos = dragInfo.pos;
\r
8776 dragInfo.start.x = dragInfo.start.y = -1;
\r
8777 dragInfo.from = dragInfo.start;
\r
8779 DrawPosition(TRUE, NULL);
\r
8786 CommentPopUp(char *title, char *str)
\r
8788 HWND hwnd = GetActiveWindow();
\r
8789 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8791 SetActiveWindow(hwnd);
\r
8795 CommentPopDown(void)
\r
8797 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8798 if (commentDialog) {
\r
8799 ShowWindow(commentDialog, SW_HIDE);
\r
8801 commentUp = FALSE;
\r
8805 EditCommentPopUp(int index, char *title, char *str)
\r
8807 EitherCommentPopUp(index, title, str, TRUE);
\r
8814 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8821 MyPlaySound(&sounds[(int)SoundMove]);
\r
8824 VOID PlayIcsWinSound()
\r
8826 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8829 VOID PlayIcsLossSound()
\r
8831 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8834 VOID PlayIcsDrawSound()
\r
8836 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8839 VOID PlayIcsUnfinishedSound()
\r
8841 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8847 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8853 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8861 consoleEcho = TRUE;
\r
8862 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8863 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8864 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8873 consoleEcho = FALSE;
\r
8874 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8875 /* This works OK: set text and background both to the same color */
\r
8877 cf.crTextColor = COLOR_ECHOOFF;
\r
8878 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8879 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8882 /* No Raw()...? */
\r
8884 void Colorize(ColorClass cc, int continuation)
\r
8886 currentColorClass = cc;
\r
8887 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8888 consoleCF.crTextColor = textAttribs[cc].color;
\r
8889 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8890 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8896 static char buf[MSG_SIZ];
\r
8897 DWORD bufsiz = MSG_SIZ;
\r
8899 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8900 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8902 if (!GetUserName(buf, &bufsiz)) {
\r
8903 /*DisplayError("Error getting user name", GetLastError());*/
\r
8904 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8912 static char buf[MSG_SIZ];
\r
8913 DWORD bufsiz = MSG_SIZ;
\r
8915 if (!GetComputerName(buf, &bufsiz)) {
\r
8916 /*DisplayError("Error getting host name", GetLastError());*/
\r
8917 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8924 ClockTimerRunning()
\r
8926 return clockTimerEvent != 0;
\r
8932 if (clockTimerEvent == 0) return FALSE;
\r
8933 KillTimer(hwndMain, clockTimerEvent);
\r
8934 clockTimerEvent = 0;
\r
8939 StartClockTimer(long millisec)
\r
8941 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8942 (UINT) millisec, NULL);
\r
8946 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8949 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8951 if(appData.noGUI) return;
\r
8952 hdc = GetDC(hwndMain);
\r
8953 if (!IsIconic(hwndMain)) {
\r
8954 DisplayAClock(hdc, timeRemaining, highlight,
\r
8955 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8957 if (highlight && iconCurrent == iconBlack) {
\r
8958 iconCurrent = iconWhite;
\r
8959 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8960 if (IsIconic(hwndMain)) {
\r
8961 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8964 (void) ReleaseDC(hwndMain, hdc);
\r
8966 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8970 DisplayBlackClock(long timeRemaining, int highlight)
\r
8973 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8976 if(appData.noGUI) return;
\r
8977 hdc = GetDC(hwndMain);
\r
8978 if (!IsIconic(hwndMain)) {
\r
8979 DisplayAClock(hdc, timeRemaining, highlight,
\r
8980 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8982 if (highlight && iconCurrent == iconWhite) {
\r
8983 iconCurrent = iconBlack;
\r
8984 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8985 if (IsIconic(hwndMain)) {
\r
8986 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8989 (void) ReleaseDC(hwndMain, hdc);
\r
8991 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8996 LoadGameTimerRunning()
\r
8998 return loadGameTimerEvent != 0;
\r
9002 StopLoadGameTimer()
\r
9004 if (loadGameTimerEvent == 0) return FALSE;
\r
9005 KillTimer(hwndMain, loadGameTimerEvent);
\r
9006 loadGameTimerEvent = 0;
\r
9011 StartLoadGameTimer(long millisec)
\r
9013 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9014 (UINT) millisec, NULL);
\r
9022 char fileTitle[MSG_SIZ];
\r
9024 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9025 f = OpenFileDialog(hwndMain, "a", defName,
\r
9026 appData.oldSaveStyle ? "gam" : "pgn",
\r
9028 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9030 SaveGame(f, 0, "");
\r
9037 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9039 if (delayedTimerEvent != 0) {
\r
9040 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9041 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9043 KillTimer(hwndMain, delayedTimerEvent);
\r
9044 delayedTimerEvent = 0;
\r
9045 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9046 delayedTimerCallback();
\r
9048 delayedTimerCallback = cb;
\r
9049 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9050 (UINT) millisec, NULL);
\r
9053 DelayedEventCallback
\r
9056 if (delayedTimerEvent) {
\r
9057 return delayedTimerCallback;
\r
9064 CancelDelayedEvent()
\r
9066 if (delayedTimerEvent) {
\r
9067 KillTimer(hwndMain, delayedTimerEvent);
\r
9068 delayedTimerEvent = 0;
\r
9072 DWORD GetWin32Priority(int nice)
\r
9073 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9075 REALTIME_PRIORITY_CLASS 0x00000100
\r
9076 HIGH_PRIORITY_CLASS 0x00000080
\r
9077 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9078 NORMAL_PRIORITY_CLASS 0x00000020
\r
9079 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9080 IDLE_PRIORITY_CLASS 0x00000040
\r
9082 if (nice < -15) return 0x00000080;
\r
9083 if (nice < 0) return 0x00008000;
\r
9084 if (nice == 0) return 0x00000020;
\r
9085 if (nice < 15) return 0x00004000;
\r
9086 return 0x00000040;
\r
9089 void RunCommand(char *cmdLine)
\r
9091 /* Now create the child process. */
\r
9092 STARTUPINFO siStartInfo;
\r
9093 PROCESS_INFORMATION piProcInfo;
\r
9095 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9096 siStartInfo.lpReserved = NULL;
\r
9097 siStartInfo.lpDesktop = NULL;
\r
9098 siStartInfo.lpTitle = NULL;
\r
9099 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9100 siStartInfo.cbReserved2 = 0;
\r
9101 siStartInfo.lpReserved2 = NULL;
\r
9102 siStartInfo.hStdInput = NULL;
\r
9103 siStartInfo.hStdOutput = NULL;
\r
9104 siStartInfo.hStdError = NULL;
\r
9106 CreateProcess(NULL,
\r
9107 cmdLine, /* command line */
\r
9108 NULL, /* process security attributes */
\r
9109 NULL, /* primary thread security attrs */
\r
9110 TRUE, /* handles are inherited */
\r
9111 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9112 NULL, /* use parent's environment */
\r
9114 &siStartInfo, /* STARTUPINFO pointer */
\r
9115 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9117 CloseHandle(piProcInfo.hThread);
\r
9120 /* Start a child process running the given program.
\r
9121 The process's standard output can be read from "from", and its
\r
9122 standard input can be written to "to".
\r
9123 Exit with fatal error if anything goes wrong.
\r
9124 Returns an opaque pointer that can be used to destroy the process
\r
9128 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9130 #define BUFSIZE 4096
\r
9132 HANDLE hChildStdinRd, hChildStdinWr,
\r
9133 hChildStdoutRd, hChildStdoutWr;
\r
9134 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9135 SECURITY_ATTRIBUTES saAttr;
\r
9137 PROCESS_INFORMATION piProcInfo;
\r
9138 STARTUPINFO siStartInfo;
\r
9140 char buf[MSG_SIZ];
\r
9143 if (appData.debugMode) {
\r
9144 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9149 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9150 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9151 saAttr.bInheritHandle = TRUE;
\r
9152 saAttr.lpSecurityDescriptor = NULL;
\r
9155 * The steps for redirecting child's STDOUT:
\r
9156 * 1. Create anonymous pipe to be STDOUT for child.
\r
9157 * 2. Create a noninheritable duplicate of read handle,
\r
9158 * and close the inheritable read handle.
\r
9161 /* Create a pipe for the child's STDOUT. */
\r
9162 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9163 return GetLastError();
\r
9166 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9167 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9168 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9169 FALSE, /* not inherited */
\r
9170 DUPLICATE_SAME_ACCESS);
\r
9172 return GetLastError();
\r
9174 CloseHandle(hChildStdoutRd);
\r
9177 * The steps for redirecting child's STDIN:
\r
9178 * 1. Create anonymous pipe to be STDIN for child.
\r
9179 * 2. Create a noninheritable duplicate of write handle,
\r
9180 * and close the inheritable write handle.
\r
9183 /* Create a pipe for the child's STDIN. */
\r
9184 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9185 return GetLastError();
\r
9188 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9189 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9190 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9191 FALSE, /* not inherited */
\r
9192 DUPLICATE_SAME_ACCESS);
\r
9194 return GetLastError();
\r
9196 CloseHandle(hChildStdinWr);
\r
9198 /* Arrange to (1) look in dir for the child .exe file, and
\r
9199 * (2) have dir be the child's working directory. Interpret
\r
9200 * dir relative to the directory WinBoard loaded from. */
\r
9201 GetCurrentDirectory(MSG_SIZ, buf);
\r
9202 SetCurrentDirectory(installDir);
\r
9203 SetCurrentDirectory(dir);
\r
9205 /* Now create the child process. */
\r
9207 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9208 siStartInfo.lpReserved = NULL;
\r
9209 siStartInfo.lpDesktop = NULL;
\r
9210 siStartInfo.lpTitle = NULL;
\r
9211 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9212 siStartInfo.cbReserved2 = 0;
\r
9213 siStartInfo.lpReserved2 = NULL;
\r
9214 siStartInfo.hStdInput = hChildStdinRd;
\r
9215 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9216 siStartInfo.hStdError = hChildStdoutWr;
\r
9218 fSuccess = CreateProcess(NULL,
\r
9219 cmdLine, /* command line */
\r
9220 NULL, /* process security attributes */
\r
9221 NULL, /* primary thread security attrs */
\r
9222 TRUE, /* handles are inherited */
\r
9223 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9224 NULL, /* use parent's environment */
\r
9226 &siStartInfo, /* STARTUPINFO pointer */
\r
9227 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9229 err = GetLastError();
\r
9230 SetCurrentDirectory(buf); /* return to prev directory */
\r
9235 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9236 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9237 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9240 /* Close the handles we don't need in the parent */
\r
9241 CloseHandle(piProcInfo.hThread);
\r
9242 CloseHandle(hChildStdinRd);
\r
9243 CloseHandle(hChildStdoutWr);
\r
9245 /* Prepare return value */
\r
9246 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9247 cp->kind = CPReal;
\r
9248 cp->hProcess = piProcInfo.hProcess;
\r
9249 cp->pid = piProcInfo.dwProcessId;
\r
9250 cp->hFrom = hChildStdoutRdDup;
\r
9251 cp->hTo = hChildStdinWrDup;
\r
9253 *pr = (void *) cp;
\r
9255 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9256 2000 where engines sometimes don't see the initial command(s)
\r
9257 from WinBoard and hang. I don't understand how that can happen,
\r
9258 but the Sleep is harmless, so I've put it in. Others have also
\r
9259 reported what may be the same problem, so hopefully this will fix
\r
9260 it for them too. */
\r
9268 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9270 ChildProc *cp; int result;
\r
9272 cp = (ChildProc *) pr;
\r
9273 if (cp == NULL) return;
\r
9275 switch (cp->kind) {
\r
9277 /* TerminateProcess is considered harmful, so... */
\r
9278 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9279 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9280 /* The following doesn't work because the chess program
\r
9281 doesn't "have the same console" as WinBoard. Maybe
\r
9282 we could arrange for this even though neither WinBoard
\r
9283 nor the chess program uses a console for stdio? */
\r
9284 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9286 /* [AS] Special termination modes for misbehaving programs... */
\r
9287 if( signal & 8 ) {
\r
9288 result = TerminateProcess( cp->hProcess, 0 );
\r
9290 if ( appData.debugMode) {
\r
9291 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9294 else if( signal & 4 ) {
\r
9295 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9297 if( dw != WAIT_OBJECT_0 ) {
\r
9298 result = TerminateProcess( cp->hProcess, 0 );
\r
9300 if ( appData.debugMode) {
\r
9301 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9307 CloseHandle(cp->hProcess);
\r
9311 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9315 closesocket(cp->sock);
\r
9320 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9321 closesocket(cp->sock);
\r
9322 closesocket(cp->sock2);
\r
9330 InterruptChildProcess(ProcRef pr)
\r
9334 cp = (ChildProc *) pr;
\r
9335 if (cp == NULL) return;
\r
9336 switch (cp->kind) {
\r
9338 /* The following doesn't work because the chess program
\r
9339 doesn't "have the same console" as WinBoard. Maybe
\r
9340 we could arrange for this even though neither WinBoard
\r
9341 nor the chess program uses a console for stdio */
\r
9342 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9347 /* Can't interrupt */
\r
9351 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9358 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9360 char cmdLine[MSG_SIZ];
\r
9362 if (port[0] == NULLCHAR) {
\r
9363 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9365 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9367 return StartChildProcess(cmdLine, "", pr);
\r
9371 /* Code to open TCP sockets */
\r
9374 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9380 struct sockaddr_in sa, mysa;
\r
9381 struct hostent FAR *hp;
\r
9382 unsigned short uport;
\r
9383 WORD wVersionRequested;
\r
9386 /* Initialize socket DLL */
\r
9387 wVersionRequested = MAKEWORD(1, 1);
\r
9388 err = WSAStartup(wVersionRequested, &wsaData);
\r
9389 if (err != 0) return err;
\r
9392 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9393 err = WSAGetLastError();
\r
9398 /* Bind local address using (mostly) don't-care values.
\r
9400 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9401 mysa.sin_family = AF_INET;
\r
9402 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9403 uport = (unsigned short) 0;
\r
9404 mysa.sin_port = htons(uport);
\r
9405 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9406 == SOCKET_ERROR) {
\r
9407 err = WSAGetLastError();
\r
9412 /* Resolve remote host name */
\r
9413 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9414 if (!(hp = gethostbyname(host))) {
\r
9415 unsigned int b0, b1, b2, b3;
\r
9417 err = WSAGetLastError();
\r
9419 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9420 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9421 hp->h_addrtype = AF_INET;
\r
9423 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9424 hp->h_addr_list[0] = (char *) malloc(4);
\r
9425 hp->h_addr_list[0][0] = (char) b0;
\r
9426 hp->h_addr_list[0][1] = (char) b1;
\r
9427 hp->h_addr_list[0][2] = (char) b2;
\r
9428 hp->h_addr_list[0][3] = (char) b3;
\r
9434 sa.sin_family = hp->h_addrtype;
\r
9435 uport = (unsigned short) atoi(port);
\r
9436 sa.sin_port = htons(uport);
\r
9437 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9439 /* Make connection */
\r
9440 if (connect(s, (struct sockaddr *) &sa,
\r
9441 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9442 err = WSAGetLastError();
\r
9447 /* Prepare return value */
\r
9448 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9449 cp->kind = CPSock;
\r
9451 *pr = (ProcRef *) cp;
\r
9457 OpenCommPort(char *name, ProcRef *pr)
\r
9462 char fullname[MSG_SIZ];
\r
9464 if (*name != '\\')
\r
9465 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9467 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9469 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9470 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9471 if (h == (HANDLE) -1) {
\r
9472 return GetLastError();
\r
9476 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9478 /* Accumulate characters until a 100ms pause, then parse */
\r
9479 ct.ReadIntervalTimeout = 100;
\r
9480 ct.ReadTotalTimeoutMultiplier = 0;
\r
9481 ct.ReadTotalTimeoutConstant = 0;
\r
9482 ct.WriteTotalTimeoutMultiplier = 0;
\r
9483 ct.WriteTotalTimeoutConstant = 0;
\r
9484 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9486 /* Prepare return value */
\r
9487 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9488 cp->kind = CPComm;
\r
9491 *pr = (ProcRef *) cp;
\r
9497 OpenLoopback(ProcRef *pr)
\r
9499 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9505 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9510 struct sockaddr_in sa, mysa;
\r
9511 struct hostent FAR *hp;
\r
9512 unsigned short uport;
\r
9513 WORD wVersionRequested;
\r
9516 char stderrPortStr[MSG_SIZ];
\r
9518 /* Initialize socket DLL */
\r
9519 wVersionRequested = MAKEWORD(1, 1);
\r
9520 err = WSAStartup(wVersionRequested, &wsaData);
\r
9521 if (err != 0) return err;
\r
9523 /* Resolve remote host name */
\r
9524 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9525 if (!(hp = gethostbyname(host))) {
\r
9526 unsigned int b0, b1, b2, b3;
\r
9528 err = WSAGetLastError();
\r
9530 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9531 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9532 hp->h_addrtype = AF_INET;
\r
9534 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9535 hp->h_addr_list[0] = (char *) malloc(4);
\r
9536 hp->h_addr_list[0][0] = (char) b0;
\r
9537 hp->h_addr_list[0][1] = (char) b1;
\r
9538 hp->h_addr_list[0][2] = (char) b2;
\r
9539 hp->h_addr_list[0][3] = (char) b3;
\r
9545 sa.sin_family = hp->h_addrtype;
\r
9546 uport = (unsigned short) 514;
\r
9547 sa.sin_port = htons(uport);
\r
9548 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9550 /* Bind local socket to unused "privileged" port address
\r
9552 s = INVALID_SOCKET;
\r
9553 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9554 mysa.sin_family = AF_INET;
\r
9555 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9556 for (fromPort = 1023;; fromPort--) {
\r
9557 if (fromPort < 0) {
\r
9559 return WSAEADDRINUSE;
\r
9561 if (s == INVALID_SOCKET) {
\r
9562 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9563 err = WSAGetLastError();
\r
9568 uport = (unsigned short) fromPort;
\r
9569 mysa.sin_port = htons(uport);
\r
9570 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9571 == SOCKET_ERROR) {
\r
9572 err = WSAGetLastError();
\r
9573 if (err == WSAEADDRINUSE) continue;
\r
9577 if (connect(s, (struct sockaddr *) &sa,
\r
9578 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9579 err = WSAGetLastError();
\r
9580 if (err == WSAEADDRINUSE) {
\r
9591 /* Bind stderr local socket to unused "privileged" port address
\r
9593 s2 = INVALID_SOCKET;
\r
9594 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9595 mysa.sin_family = AF_INET;
\r
9596 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9597 for (fromPort = 1023;; fromPort--) {
\r
9598 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9599 if (fromPort < 0) {
\r
9600 (void) closesocket(s);
\r
9602 return WSAEADDRINUSE;
\r
9604 if (s2 == INVALID_SOCKET) {
\r
9605 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9606 err = WSAGetLastError();
\r
9612 uport = (unsigned short) fromPort;
\r
9613 mysa.sin_port = htons(uport);
\r
9614 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9615 == SOCKET_ERROR) {
\r
9616 err = WSAGetLastError();
\r
9617 if (err == WSAEADDRINUSE) continue;
\r
9618 (void) closesocket(s);
\r
9622 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9623 err = WSAGetLastError();
\r
9624 if (err == WSAEADDRINUSE) {
\r
9626 s2 = INVALID_SOCKET;
\r
9629 (void) closesocket(s);
\r
9630 (void) closesocket(s2);
\r
9636 prevStderrPort = fromPort; // remember port used
\r
9637 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9639 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9640 err = WSAGetLastError();
\r
9641 (void) closesocket(s);
\r
9642 (void) closesocket(s2);
\r
9647 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9648 err = WSAGetLastError();
\r
9649 (void) closesocket(s);
\r
9650 (void) closesocket(s2);
\r
9654 if (*user == NULLCHAR) user = UserName();
\r
9655 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9656 err = WSAGetLastError();
\r
9657 (void) closesocket(s);
\r
9658 (void) closesocket(s2);
\r
9662 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9663 err = WSAGetLastError();
\r
9664 (void) closesocket(s);
\r
9665 (void) closesocket(s2);
\r
9670 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9671 err = WSAGetLastError();
\r
9672 (void) closesocket(s);
\r
9673 (void) closesocket(s2);
\r
9677 (void) closesocket(s2); /* Stop listening */
\r
9679 /* Prepare return value */
\r
9680 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9681 cp->kind = CPRcmd;
\r
9684 *pr = (ProcRef *) cp;
\r
9691 AddInputSource(ProcRef pr, int lineByLine,
\r
9692 InputCallback func, VOIDSTAR closure)
\r
9694 InputSource *is, *is2 = NULL;
\r
9695 ChildProc *cp = (ChildProc *) pr;
\r
9697 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9698 is->lineByLine = lineByLine;
\r
9700 is->closure = closure;
\r
9701 is->second = NULL;
\r
9702 is->next = is->buf;
\r
9703 if (pr == NoProc) {
\r
9704 is->kind = CPReal;
\r
9705 consoleInputSource = is;
\r
9707 is->kind = cp->kind;
\r
9709 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9710 we create all threads suspended so that the is->hThread variable can be
\r
9711 safely assigned, then let the threads start with ResumeThread.
\r
9713 switch (cp->kind) {
\r
9715 is->hFile = cp->hFrom;
\r
9716 cp->hFrom = NULL; /* now owned by InputThread */
\r
9718 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9719 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9723 is->hFile = cp->hFrom;
\r
9724 cp->hFrom = NULL; /* now owned by InputThread */
\r
9726 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9727 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9731 is->sock = cp->sock;
\r
9733 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9734 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9738 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9740 is->sock = cp->sock;
\r
9742 is2->sock = cp->sock2;
\r
9743 is2->second = is2;
\r
9745 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9746 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9748 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9749 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9753 if( is->hThread != NULL ) {
\r
9754 ResumeThread( is->hThread );
\r
9757 if( is2 != NULL && is2->hThread != NULL ) {
\r
9758 ResumeThread( is2->hThread );
\r
9762 return (InputSourceRef) is;
\r
9766 RemoveInputSource(InputSourceRef isr)
\r
9770 is = (InputSource *) isr;
\r
9771 is->hThread = NULL; /* tell thread to stop */
\r
9772 CloseHandle(is->hThread);
\r
9773 if (is->second != NULL) {
\r
9774 is->second->hThread = NULL;
\r
9775 CloseHandle(is->second->hThread);
\r
9779 int no_wrap(char *message, int count)
\r
9781 ConsoleOutput(message, count, FALSE);
\r
9786 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9789 int outCount = SOCKET_ERROR;
\r
9790 ChildProc *cp = (ChildProc *) pr;
\r
9791 static OVERLAPPED ovl;
\r
9793 static int line = 0;
\r
9797 if (appData.noJoin || !appData.useInternalWrap)
\r
9798 return no_wrap(message, count);
\r
9801 int width = get_term_width();
\r
9802 int len = wrap(NULL, message, count, width, &line);
\r
9803 char *msg = malloc(len);
\r
9807 return no_wrap(message, count);
\r
9810 dbgchk = wrap(msg, message, count, width, &line);
\r
9811 if (dbgchk != len && appData.debugMode)
\r
9812 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9813 ConsoleOutput(msg, len, FALSE);
\r
9820 if (ovl.hEvent == NULL) {
\r
9821 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9823 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9825 switch (cp->kind) {
\r
9828 outCount = send(cp->sock, message, count, 0);
\r
9829 if (outCount == SOCKET_ERROR) {
\r
9830 *outError = WSAGetLastError();
\r
9832 *outError = NO_ERROR;
\r
9837 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9838 &dOutCount, NULL)) {
\r
9839 *outError = NO_ERROR;
\r
9840 outCount = (int) dOutCount;
\r
9842 *outError = GetLastError();
\r
9847 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9848 &dOutCount, &ovl);
\r
9849 if (*outError == NO_ERROR) {
\r
9850 outCount = (int) dOutCount;
\r
9860 if(n != 0) Sleep(n);
\r
9864 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9867 /* Ignore delay, not implemented for WinBoard */
\r
9868 return OutputToProcess(pr, message, count, outError);
\r
9873 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9874 char *buf, int count, int error)
\r
9876 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9879 /* see wgamelist.c for Game List functions */
\r
9880 /* see wedittags.c for Edit Tags functions */
\r
9887 char buf[MSG_SIZ];
\r
9890 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9891 f = fopen(buf, "r");
\r
9893 ProcessICSInitScript(f);
\r
9903 StartAnalysisClock()
\r
9905 if (analysisTimerEvent) return;
\r
9906 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9907 (UINT) 2000, NULL);
\r
9911 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9913 highlightInfo.sq[0].x = fromX;
\r
9914 highlightInfo.sq[0].y = fromY;
\r
9915 highlightInfo.sq[1].x = toX;
\r
9916 highlightInfo.sq[1].y = toY;
\r
9922 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9923 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9927 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9929 premoveHighlightInfo.sq[0].x = fromX;
\r
9930 premoveHighlightInfo.sq[0].y = fromY;
\r
9931 premoveHighlightInfo.sq[1].x = toX;
\r
9932 premoveHighlightInfo.sq[1].y = toY;
\r
9936 ClearPremoveHighlights()
\r
9938 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9939 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9943 ShutDownFrontEnd()
\r
9945 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9946 DeleteClipboardTempFiles();
\r
9952 if (IsIconic(hwndMain))
\r
9953 ShowWindow(hwndMain, SW_RESTORE);
\r
9955 SetActiveWindow(hwndMain);
\r
9959 * Prototypes for animation support routines
\r
9961 static void ScreenSquare(int column, int row, POINT * pt);
\r
9962 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9963 POINT frames[], int * nFrames);
\r
9969 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9970 { // [HGM] atomic: animate blast wave
\r
9973 explodeInfo.fromX = fromX;
\r
9974 explodeInfo.fromY = fromY;
\r
9975 explodeInfo.toX = toX;
\r
9976 explodeInfo.toY = toY;
\r
9977 for(i=1; i<4*kFactor; i++) {
\r
9978 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9979 DrawPosition(FALSE, board);
\r
9980 Sleep(appData.animSpeed);
\r
9982 explodeInfo.radius = 0;
\r
9983 DrawPosition(TRUE, board);
\r
9987 AnimateMove(board, fromX, fromY, toX, toY)
\r
9994 ChessSquare piece;
\r
9995 int x = toX, y = toY;
\r
9996 POINT start, finish, mid;
\r
9997 POINT frames[kFactor * 2 + 1];
\r
10000 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
10002 if (!appData.animate) return;
\r
10003 if (doingSizing) return;
\r
10004 if (fromY < 0 || fromX < 0) return;
\r
10005 piece = board[fromY][fromX];
\r
10006 if (piece >= EmptySquare) return;
\r
10008 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10012 ScreenSquare(fromX, fromY, &start);
\r
10013 ScreenSquare(toX, toY, &finish);
\r
10015 /* All moves except knight jumps move in straight line */
\r
10016 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10017 mid.x = start.x + (finish.x - start.x) / 2;
\r
10018 mid.y = start.y + (finish.y - start.y) / 2;
\r
10020 /* Knight: make straight movement then diagonal */
\r
10021 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10022 mid.x = start.x + (finish.x - start.x) / 2;
\r
10026 mid.y = start.y + (finish.y - start.y) / 2;
\r
10030 /* Don't use as many frames for very short moves */
\r
10031 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10032 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10034 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10036 animInfo.from.x = fromX;
\r
10037 animInfo.from.y = fromY;
\r
10038 animInfo.to.x = toX;
\r
10039 animInfo.to.y = toY;
\r
10040 animInfo.lastpos = start;
\r
10041 animInfo.piece = piece;
\r
10042 for (n = 0; n < nFrames; n++) {
\r
10043 animInfo.pos = frames[n];
\r
10044 DrawPosition(FALSE, NULL);
\r
10045 animInfo.lastpos = animInfo.pos;
\r
10046 Sleep(appData.animSpeed);
\r
10048 animInfo.pos = finish;
\r
10049 DrawPosition(FALSE, NULL);
\r
10051 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10053 animInfo.piece = EmptySquare;
\r
10054 Explode(board, fromX, fromY, toX, toY);
\r
10057 /* Convert board position to corner of screen rect and color */
\r
10060 ScreenSquare(column, row, pt)
\r
10061 int column; int row; POINT * pt;
\r
10064 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10065 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10067 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10068 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10072 /* Generate a series of frame coords from start->mid->finish.
\r
10073 The movement rate doubles until the half way point is
\r
10074 reached, then halves back down to the final destination,
\r
10075 which gives a nice slow in/out effect. The algorithmn
\r
10076 may seem to generate too many intermediates for short
\r
10077 moves, but remember that the purpose is to attract the
\r
10078 viewers attention to the piece about to be moved and
\r
10079 then to where it ends up. Too few frames would be less
\r
10083 Tween(start, mid, finish, factor, frames, nFrames)
\r
10084 POINT * start; POINT * mid;
\r
10085 POINT * finish; int factor;
\r
10086 POINT frames[]; int * nFrames;
\r
10088 int n, fraction = 1, count = 0;
\r
10090 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10091 for (n = 0; n < factor; n++)
\r
10093 for (n = 0; n < factor; n++) {
\r
10094 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10095 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10097 fraction = fraction / 2;
\r
10101 frames[count] = *mid;
\r
10104 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10106 for (n = 0; n < factor; n++) {
\r
10107 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10108 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10110 fraction = fraction * 2;
\r
10112 *nFrames = count;
\r
10116 SettingsPopUp(ChessProgramState *cps)
\r
10117 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10118 EngineOptionsPopup(savedHwnd, cps);
\r
10121 int flock(int fid, int code)
\r
10123 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10125 ov.hEvent = NULL;
\r
10127 ov.OffsetHigh = 0;
\r
10129 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10131 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10132 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10133 default: return -1;
\r
10142 static char col[8][20];
\r
10143 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10145 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10150 ActivateTheme (int new)
\r
10151 { // Redo initialization of features depending on options that can occur in themes
\r
10153 if(new) InitDrawingColors();
\r
10154 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10155 InitDrawingSizes(boardSize, 0);
\r
10156 InvalidateRect(hwndMain, NULL, TRUE);
\r