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
2592 pieceBitmap[i][piece] = NULL;
\r
2596 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
2598 // Orthodox Chess pieces
\r
2599 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
2600 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
2601 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
2602 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
2603 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
2604 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
2605 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
2606 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
2607 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
2608 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
2609 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
2610 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
2611 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
2612 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
2613 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
2614 if( gameInfo.variant == VariantShogi && squareSize <= 72 && squareSize >= 33) {
\r
2615 // in Shogi, Hijack the unused Queen for Lance
\r
2616 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2617 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2618 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2620 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
2621 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
2622 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
2625 if(squareSize <= 72 && squareSize >= 33) {
\r
2626 /* A & C are available in most sizes now */
\r
2627 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
2628 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2629 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2630 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2631 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2632 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2633 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2634 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2635 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2636 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2637 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2638 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2639 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2640 } else { // Smirf-like
\r
2641 if(gameInfo.variant == VariantSChess) {
\r
2642 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2643 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2644 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2646 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
2647 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
2648 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
2651 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
2652 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2653 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2654 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2655 } else if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
\r
2656 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2657 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2658 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2659 } else { // WinBoard standard
\r
2660 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
2661 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
2662 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
2667 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
2668 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
2669 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
2670 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
2671 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
2672 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
2673 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2674 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
2675 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
2676 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
2677 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
2678 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
2679 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
2680 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
2681 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
2682 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
2683 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
2684 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
2685 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
2686 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
2687 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
2688 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
2689 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
2690 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
2691 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
2692 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
2693 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
2694 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
2695 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
2696 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
2697 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
2698 pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");
\r
2699 pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");
\r
2700 pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");
\r
2702 if(gameInfo.variant == VariantShogi && BOARD_HEIGHT != 7) { /* promoted Gold representations (but not in Tori!)*/
\r
2703 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
2704 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
2705 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2706 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
2707 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
2708 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2709 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
2710 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
2711 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2712 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
2713 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
2714 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
2716 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
2717 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
2718 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
2719 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
2720 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
2721 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
2722 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
2723 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
2724 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
2725 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
2726 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
2727 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
2730 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
2731 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
2732 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
2733 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
2734 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
2735 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
2736 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
2737 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
2738 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
2739 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
2740 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
2741 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
2742 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
2743 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
2744 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
2748 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
2749 /* special Shogi support in this size */
\r
2750 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
2751 for (piece = WhitePawn;
\r
2752 (int) piece < (int) BlackPawn;
\r
2753 piece = (ChessSquare) ((int) piece + 1)) {
\r
2754 if (pieceBitmap[i][piece] != NULL)
\r
2755 DeleteObject(pieceBitmap[i][piece]);
\r
2758 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2759 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2760 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2761 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2762 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2763 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2764 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2765 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2766 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2767 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2768 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2769 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2770 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2771 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2772 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
2773 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
2774 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
2775 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
2776 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
2777 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
2778 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
2779 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
2780 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
2781 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
2782 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
2783 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
2784 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
2785 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
2786 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2787 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2788 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2789 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2790 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2791 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
2792 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2793 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2794 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
2795 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
2796 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2797 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
2798 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
2799 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
2803 if(appData.pieceDirectory[0]) for(i=WhitePawn; i<BlackPawn; i++) { // try for all missing pieces with new naming convention
\r
2804 char buf[MSG_SIZ];
\r
2805 if(pieceBitmap[0][i]) continue;
\r
2806 snprintf(buf, MSG_SIZ, "piece%d_", i);
\r
2807 pieceBitmap[0][i] = DoLoadBitmap(hInst, buf, squareSize, "s");
\r
2808 pieceBitmap[1][i] = DoLoadBitmap(hInst, buf, squareSize, "o");
\r
2809 pieceBitmap[2][i] = DoLoadBitmap(hInst, buf, squareSize, "w");
\r
2814 PieceBitmap(ChessSquare p, int kind)
\r
2816 if ((int) p >= (int) BlackPawn)
\r
2817 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
2819 return pieceBitmap[kind][(int) p];
\r
2822 /***************************************************************/
\r
2824 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
2825 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
2827 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
2828 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
2832 SquareToPos(int row, int column, int * x, int * y)
\r
2835 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
2836 *y = boardRect.top + lineGap + row * (squareSize + lineGap) + border;
\r
2838 *x = boardRect.left + lineGap + column * (squareSize + lineGap) + border;
\r
2839 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
2844 DrawCoordsOnDC(HDC hdc)
\r
2846 static char files[] = "0123456789012345678901221098765432109876543210";
\r
2847 static char ranks[] = "wvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvw";
\r
2848 char str[2] = { NULLCHAR, NULLCHAR };
\r
2849 int oldMode, oldAlign, x, y, start, i;
\r
2853 if (!appData.showCoords)
\r
2856 start = flipView ? 1-(ONE!='1') : 45+(ONE!='1')-BOARD_HEIGHT;
\r
2858 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
2859 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
2860 oldAlign = GetTextAlign(hdc);
\r
2861 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
2863 y = boardRect.top + lineGap;
\r
2864 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
2867 SetTextAlign(hdc, TA_RIGHT|TA_TOP);
\r
2868 x += border - lineGap - 4; y += squareSize - 6;
\r
2870 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2871 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
2872 str[0] = files[start + i];
\r
2873 ExtTextOut(hdc, x + 2 - (border ? gameInfo.holdingsWidth * (squareSize + lineGap) : 0), y + 1, 0, NULL, str, 1, NULL);
\r
2874 y += squareSize + lineGap;
\r
2877 start = flipView ? 23-(BOARD_RGHT-BOARD_LEFT) : 23;
\r
2880 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
2881 x += -border + 4; y += border - squareSize + 6;
\r
2883 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
2884 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
2885 str[0] = ranks[start + i];
\r
2886 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
2887 x += squareSize + lineGap;
\r
2890 SelectObject(hdc, oldBrush);
\r
2891 SetBkMode(hdc, oldMode);
\r
2892 SetTextAlign(hdc, oldAlign);
\r
2893 SelectObject(hdc, oldFont);
\r
2897 DrawGridOnDC(HDC hdc)
\r
2901 if (lineGap != 0) {
\r
2902 oldPen = SelectObject(hdc, gridPen);
\r
2903 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
2904 SelectObject(hdc, oldPen);
\r
2908 #define HIGHLIGHT_PEN 0
\r
2909 #define PREMOVE_PEN 1
\r
2912 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
2915 HPEN oldPen, hPen;
\r
2916 if (lineGap == 0) return;
\r
2918 x1 = boardRect.left +
\r
2919 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap) + border;
\r
2920 y1 = boardRect.top +
\r
2921 lineGap/2 + y * (squareSize + lineGap) + border;
\r
2923 x1 = boardRect.left +
\r
2924 lineGap/2 + x * (squareSize + lineGap) + border;
\r
2925 y1 = boardRect.top +
\r
2926 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap) + border;
\r
2928 hPen = pen ? premovePen : highlightPen;
\r
2929 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
2930 MoveToEx(hdc, x1, y1, NULL);
\r
2931 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
2932 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
2933 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
2934 LineTo(hdc, x1, y1);
\r
2935 SelectObject(hdc, oldPen);
\r
2939 DrawHighlightsOnDC(HDC hdc, HighlightInfo *h, int pen)
\r
2942 for (i=0; i<2; i++) {
\r
2943 if (h->sq[i].x >= 0 && h->sq[i].y >= 0)
\r
2944 DrawHighlightOnDC(hdc, TRUE,
\r
2945 h->sq[i].x, h->sq[i].y,
\r
2950 /* Note: sqcolor is used only in monoMode */
\r
2951 /* Note that this code is largely duplicated in woptions.c,
\r
2952 function DrawSampleSquare, so that needs to be updated too */
\r
2954 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
2956 HBITMAP oldBitmap;
\r
2960 if (appData.blindfold) return;
\r
2962 /* [AS] Use font-based pieces if needed */
\r
2963 if( fontBitmapSquareSize >= 0 && (squareSize > 32 || gameInfo.variant >= VariantShogi)) {
\r
2964 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
2965 CreatePiecesFromFont();
\r
2967 if( fontBitmapSquareSize == squareSize ) {
\r
2968 int index = TranslatePieceToFontPiece(piece);
\r
2970 SelectObject( tmphdc, hPieceMask[ index ] );
\r
2972 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2973 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCAND);
\r
2977 squareSize, squareSize,
\r
2982 SelectObject( tmphdc, hPieceFace[ index ] );
\r
2984 if(appData.upsideDown ? color==flipView : (flipView && gameInfo.variant == VariantShogi))
\r
2985 StretchBlt(hdc, x+squareSize, y+squareSize, -squareSize, -squareSize, tmphdc, 0, 0, squareSize, squareSize, SRCPAINT);
\r
2989 squareSize, squareSize,
\r
2998 if (appData.monoMode) {
\r
2999 SelectObject(tmphdc, PieceBitmap(piece,
\r
3000 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3001 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3002 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3004 HBRUSH xBrush = whitePieceBrush;
\r
3005 tmpSize = squareSize;
\r
3006 if(appData.pieceDirectory[0]) xBrush = GetStockObject(WHITE_BRUSH);
\r
3008 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3009 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3010 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3011 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3012 x += (squareSize - minorSize)>>1;
\r
3013 y += squareSize - minorSize - 2;
\r
3014 tmpSize = minorSize;
\r
3016 if (color || appData.allWhite ) {
\r
3017 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3019 oldBrush = SelectObject(hdc, xBrush);
\r
3020 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3021 if(appData.upsideDown && color==flipView)
\r
3022 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3024 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3025 /* Use black for outline of white pieces */
\r
3026 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3027 if(appData.upsideDown && color==flipView)
\r
3028 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3030 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3031 } else if(appData.pieceDirectory[0]) {
\r
3032 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3033 oldBrush = SelectObject(hdc, xBrush);
\r
3034 if(appData.upsideDown && color==flipView)
\r
3035 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3037 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3038 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3039 if(appData.upsideDown && color==flipView)
\r
3040 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3042 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3044 /* Use square color for details of black pieces */
\r
3045 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3046 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3047 if(appData.upsideDown && !flipView)
\r
3048 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3050 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3052 SelectObject(hdc, oldBrush);
\r
3053 SelectObject(tmphdc, oldBitmap);
\r
3057 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3058 int GetBackTextureMode( int algo )
\r
3060 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3064 case BACK_TEXTURE_MODE_PLAIN:
\r
3065 result = 1; /* Always use identity map */
\r
3067 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3068 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3076 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3077 to handle redraws cleanly (as random numbers would always be different).
\r
3079 VOID RebuildTextureSquareInfo()
\r
3089 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3091 if( liteBackTexture != NULL ) {
\r
3092 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3093 lite_w = bi.bmWidth;
\r
3094 lite_h = bi.bmHeight;
\r
3098 if( darkBackTexture != NULL ) {
\r
3099 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3100 dark_w = bi.bmWidth;
\r
3101 dark_h = bi.bmHeight;
\r
3105 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3106 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3107 if( (col + row) & 1 ) {
\r
3109 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3110 if( lite_w >= squareSize*BOARD_WIDTH )
\r
3111 backTextureSquareInfo[row][col].x = (2*col+1)*lite_w/(2*BOARD_WIDTH) - squareSize/2; /* [HGM] cut out of center of virtual square */
\r
3113 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3114 if( lite_h >= squareSize*BOARD_HEIGHT )
\r
3115 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1)*lite_h/(2*BOARD_HEIGHT) - squareSize/2;
\r
3117 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3118 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3123 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3124 if( dark_w >= squareSize*BOARD_WIDTH )
\r
3125 backTextureSquareInfo[row][col].x = (2*col+1) * dark_w / (2*BOARD_WIDTH) - squareSize/2;
\r
3127 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3128 if( dark_h >= squareSize*BOARD_HEIGHT )
\r
3129 backTextureSquareInfo[row][col].y = (2*(BOARD_HEIGHT-row)-1) * dark_h / (2*BOARD_HEIGHT) - squareSize/2;
\r
3131 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3132 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3139 /* [AS] Arrow highlighting support */
\r
3141 static double A_WIDTH = 5; /* Width of arrow body */
\r
3143 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3144 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3146 static double Sqr( double x )
\r
3151 static int Round( double x )
\r
3153 return (int) (x + 0.5);
\r
3156 /* Draw an arrow between two points using current settings */
\r
3157 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3160 double dx, dy, j, k, x, y;
\r
3162 if( d_x == s_x ) {
\r
3163 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3165 arrow[0].x = s_x + A_WIDTH + 0.5;
\r
3168 arrow[1].x = s_x + A_WIDTH + 0.5;
\r
3169 arrow[1].y = d_y - h;
\r
3171 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3172 arrow[2].y = d_y - h;
\r
3177 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3178 arrow[5].y = d_y - h;
\r
3180 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3181 arrow[4].y = d_y - h;
\r
3183 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
\r
3186 else if( d_y == s_y ) {
\r
3187 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3190 arrow[0].y = s_y + A_WIDTH + 0.5;
\r
3192 arrow[1].x = d_x - w;
\r
3193 arrow[1].y = s_y + A_WIDTH + 0.5;
\r
3195 arrow[2].x = d_x - w;
\r
3196 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3201 arrow[5].x = d_x - w;
\r
3202 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3204 arrow[4].x = d_x - w;
\r
3205 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
\r
3208 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
\r
3211 /* [AS] Needed a lot of paper for this! :-) */
\r
3212 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3213 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3215 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3217 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3222 arrow[0].x = Round(x - j);
\r
3223 arrow[0].y = Round(y + j*dx);
\r
3225 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
\r
3226 arrow[1].y = Round(arrow[0].y - 2*j*dx);
\r
3229 x = (double) d_x - k;
\r
3230 y = (double) d_y - k*dy;
\r
3233 x = (double) d_x + k;
\r
3234 y = (double) d_y + k*dy;
\r
3237 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
\r
3239 arrow[6].x = Round(x - j);
\r
3240 arrow[6].y = Round(y + j*dx);
\r
3242 arrow[2].x = Round(arrow[6].x + 2*j);
\r
3243 arrow[2].y = Round(arrow[6].y - 2*j*dx);
\r
3245 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
\r
3246 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
\r
3251 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
\r
3252 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
\r
3255 Polygon( hdc, arrow, 7 );
\r
3258 /* [AS] Draw an arrow between two squares */
\r
3259 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3261 int s_x, s_y, d_x, d_y;
\r
3268 if( s_col == d_col && s_row == d_row ) {
\r
3272 /* Get source and destination points */
\r
3273 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3274 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3277 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
\r
3279 else if( d_y < s_y ) {
\r
3280 d_y += squareSize / 2 + squareSize / 4;
\r
3283 d_y += squareSize / 2;
\r
3287 d_x += squareSize / 2 - squareSize / 4;
\r
3289 else if( d_x < s_x ) {
\r
3290 d_x += squareSize / 2 + squareSize / 4;
\r
3293 d_x += squareSize / 2;
\r
3296 s_x += squareSize / 2;
\r
3297 s_y += squareSize / 2;
\r
3299 /* Adjust width */
\r
3300 A_WIDTH = squareSize / 14.; //[HGM] make float
\r
3303 stLB.lbStyle = BS_SOLID;
\r
3304 stLB.lbColor = appData.highlightArrowColor;
\r
3307 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3308 holdpen = SelectObject( hdc, hpen );
\r
3309 hbrush = CreateBrushIndirect( &stLB );
\r
3310 holdbrush = SelectObject( hdc, hbrush );
\r
3312 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3314 SelectObject( hdc, holdpen );
\r
3315 SelectObject( hdc, holdbrush );
\r
3316 DeleteObject( hpen );
\r
3317 DeleteObject( hbrush );
\r
3320 BOOL HasHighlightInfo()
\r
3322 BOOL result = FALSE;
\r
3324 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3325 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3336 BOOL IsDrawArrowEnabled()
\r
3338 BOOL result = FALSE;
\r
3340 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3347 VOID DrawArrowHighlight( HDC hdc )
\r
3349 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3350 DrawArrowBetweenSquares( hdc,
\r
3351 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3352 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3356 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3358 HRGN result = NULL;
\r
3360 if( HasHighlightInfo() ) {
\r
3361 int x1, y1, x2, y2;
\r
3362 int sx, sy, dx, dy;
\r
3364 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3365 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3367 sx = MIN( x1, x2 );
\r
3368 sy = MIN( y1, y2 );
\r
3369 dx = MAX( x1, x2 ) + squareSize;
\r
3370 dy = MAX( y1, y2 ) + squareSize;
\r
3372 result = CreateRectRgn( sx, sy, dx, dy );
\r
3379 Warning: this function modifies the behavior of several other functions.
\r
3381 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3382 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3383 repaint is scattered all over the place, which is not good for features such as
\r
3384 "arrow highlighting" that require a full repaint of the board.
\r
3386 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3387 user interaction, when speed is not so important) but especially to avoid errors
\r
3388 in the displayed graphics.
\r
3390 In such patched places, I always try refer to this function so there is a single
\r
3391 place to maintain knowledge.
\r
3393 To restore the original behavior, just return FALSE unconditionally.
\r
3395 BOOL IsFullRepaintPreferrable()
\r
3397 BOOL result = FALSE;
\r
3399 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3400 /* Arrow may appear on the board */
\r
3408 This function is called by DrawPosition to know whether a full repaint must
\r
3411 Only DrawPosition may directly call this function, which makes use of
\r
3412 some state information. Other function should call DrawPosition specifying
\r
3413 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3415 BOOL DrawPositionNeedsFullRepaint()
\r
3417 BOOL result = FALSE;
\r
3420 Probably a slightly better policy would be to trigger a full repaint
\r
3421 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3422 but animation is fast enough that it's difficult to notice.
\r
3424 if( animInfo.piece == EmptySquare ) {
\r
3425 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
3433 static HBITMAP borderBitmap;
\r
3436 DrawBackgroundOnDC(HDC hdc)
\r
3442 static char oldBorder[MSG_SIZ];
\r
3443 int w = 600, h = 600, mode;
\r
3445 if(strcmp(appData.border, oldBorder)) { // load new one when old one no longer valid
\r
3446 strncpy(oldBorder, appData.border, MSG_SIZ-1);
\r
3447 borderBitmap = LoadImage( 0, appData.border, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
3449 if(borderBitmap == NULL) { // loading failed, use white
\r
3450 FillRect( hdc, &boardRect, whitePieceBrush );
\r
3453 tmphdc = CreateCompatibleDC(hdc);
\r
3454 hbm = SelectObject(tmphdc, borderBitmap);
\r
3455 if( GetObject( borderBitmap, sizeof(bi), &bi ) > 0 ) {
\r
3459 mode = SetStretchBltMode(hdc, COLORONCOLOR);
\r
3460 StretchBlt(hdc, boardRect.left, boardRect.top, boardRect.right - boardRect.left,
\r
3461 boardRect.bottom - boardRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3462 SetStretchBltMode(hdc, mode);
\r
3463 SelectObject(tmphdc, hbm);
\r
3468 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3470 int row, column, x, y, square_color, piece_color;
\r
3471 ChessSquare piece;
\r
3473 HDC texture_hdc = NULL;
\r
3475 /* [AS] Initialize background textures if needed */
\r
3476 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3477 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
3478 if( backTextureSquareSize != squareSize
\r
3479 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
3480 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
3481 backTextureSquareSize = squareSize;
\r
3482 RebuildTextureSquareInfo();
\r
3485 texture_hdc = CreateCompatibleDC( hdc );
\r
3488 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3489 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3491 SquareToPos(row, column, &x, &y);
\r
3493 piece = board[row][column];
\r
3495 square_color = ((column + row) % 2) == 1;
\r
3496 if( gameInfo.variant == VariantXiangqi ) {
\r
3497 square_color = !InPalace(row, column);
\r
3498 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3499 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3501 piece_color = (int) piece < (int) BlackPawn;
\r
3504 /* [HGM] holdings file: light square or black */
\r
3505 if(column == BOARD_LEFT-2) {
\r
3506 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3509 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3513 if(column == BOARD_RGHT + 1 ) {
\r
3514 if( row < gameInfo.holdingsSize )
\r
3517 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3521 if(column == BOARD_LEFT-1 ) /* left align */
\r
3522 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
3523 else if( column == BOARD_RGHT) /* right align */
\r
3524 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
3525 else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3527 if (appData.monoMode) {
\r
3528 if (piece == EmptySquare) {
\r
3529 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3530 square_color ? WHITENESS : BLACKNESS);
\r
3532 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3535 else if( appData.useBitmaps && backTextureSquareInfo[row][column].mode > 0 ) {
\r
3536 /* [AS] Draw the square using a texture bitmap */
\r
3537 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3538 int r = row, c = column; // [HGM] do not flip board in flipView
\r
3539 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
3542 squareSize, squareSize,
\r
3545 backTextureSquareInfo[r][c].mode,
\r
3546 backTextureSquareInfo[r][c].x,
\r
3547 backTextureSquareInfo[r][c].y );
\r
3549 SelectObject( texture_hdc, hbm );
\r
3551 if (piece != EmptySquare) {
\r
3552 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3556 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3558 oldBrush = SelectObject(hdc, brush );
\r
3559 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3560 SelectObject(hdc, oldBrush);
\r
3561 if (piece != EmptySquare)
\r
3562 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3567 if( texture_hdc != NULL ) {
\r
3568 DeleteDC( texture_hdc );
\r
3572 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
3573 void fputDW(FILE *f, int x)
\r
3575 fputc(x & 255, f);
\r
3576 fputc(x>>8 & 255, f);
\r
3577 fputc(x>>16 & 255, f);
\r
3578 fputc(x>>24 & 255, f);
\r
3581 #define MAX_CLIPS 200 /* more than enough */
\r
3584 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
3586 // HBITMAP bufferBitmap;
\r
3591 int w = 100, h = 50;
\r
3593 if(logo == NULL) {
\r
3594 if(!logoHeight) return;
\r
3595 FillRect( hdc, &logoRect, whitePieceBrush );
\r
3597 // GetClientRect(hwndMain, &Rect);
\r
3598 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3599 // Rect.bottom-Rect.top+1);
\r
3600 tmphdc = CreateCompatibleDC(hdc);
\r
3601 hbm = SelectObject(tmphdc, logo);
\r
3602 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
3606 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
3607 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
3608 SelectObject(tmphdc, hbm);
\r
3616 HDC hdc = GetDC(hwndMain);
\r
3617 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
3618 if(appData.autoLogo) {
\r
3620 switch(gameMode) { // pick logos based on game mode
\r
3621 case IcsObserving:
\r
3622 whiteLogo = second.programLogo; // ICS logo
\r
3623 blackLogo = second.programLogo;
\r
3626 case IcsPlayingWhite:
\r
3627 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
3628 blackLogo = second.programLogo; // ICS logo
\r
3630 case IcsPlayingBlack:
\r
3631 whiteLogo = second.programLogo; // ICS logo
\r
3632 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
3634 case TwoMachinesPlay:
\r
3635 if(first.twoMachinesColor[0] == 'b') {
\r
3636 whiteLogo = second.programLogo;
\r
3637 blackLogo = first.programLogo;
\r
3640 case MachinePlaysWhite:
\r
3641 blackLogo = userLogo;
\r
3643 case MachinePlaysBlack:
\r
3644 whiteLogo = userLogo;
\r
3645 blackLogo = first.programLogo;
\r
3648 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
3649 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
3650 ReleaseDC(hwndMain, hdc);
\r
3655 UpdateLogos(int display)
\r
3656 { // called after loading new engine(s), in tourney or from menu
\r
3657 LoadLogo(&first, 0, FALSE);
\r
3658 LoadLogo(&second, 1, appData.icsActive);
\r
3659 InitDrawingSizes(-2, 0); // adapt layout of board window to presence/absence of logos
\r
3660 if(display) DisplayLogos();
\r
3663 static HDC hdcSeek;
\r
3665 // [HGM] seekgraph
\r
3666 void DrawSeekAxis( int x, int y, int xTo, int yTo )
\r
3669 HPEN hp = SelectObject( hdcSeek, gridPen );
\r
3670 MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );
\r
3671 LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );
\r
3672 SelectObject( hdcSeek, hp );
\r
3675 // front-end wrapper for drawing functions to do rectangles
\r
3676 void DrawSeekBackground( int left, int top, int right, int bottom )
\r
3681 if (hdcSeek == NULL) {
\r
3682 hdcSeek = GetDC(hwndMain);
\r
3683 if (!appData.monoMode) {
\r
3684 SelectPalette(hdcSeek, hPal, FALSE);
\r
3685 RealizePalette(hdcSeek);
\r
3688 hp = SelectObject( hdcSeek, gridPen );
\r
3689 rc.top = boardRect.top+top; rc.left = boardRect.left+left;
\r
3690 rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;
\r
3691 FillRect( hdcSeek, &rc, lightSquareBrush );
\r
3692 SelectObject( hdcSeek, hp );
\r
3695 // front-end wrapper for putting text in graph
\r
3696 void DrawSeekText(char *buf, int x, int y)
\r
3699 SetBkMode( hdcSeek, TRANSPARENT );
\r
3700 GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );
\r
3701 TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );
\r
3704 void DrawSeekDot(int x, int y, int color)
\r
3706 int square = color & 0x80;
\r
3707 HBRUSH oldBrush = SelectObject(hdcSeek,
\r
3708 color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);
\r
3711 Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,
\r
3712 boardRect.left+x + squareSize/9, boardRect.top+y + squareSize/9);
\r
3714 Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,
\r
3715 boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);
\r
3716 SelectObject(hdcSeek, oldBrush);
\r
3719 void DrawSeekOpen()
\r
3723 void DrawSeekClose()
\r
3728 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3730 static Board lastReq[2], lastDrawn[2];
\r
3731 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3732 static int lastDrawnFlipView = 0;
\r
3733 static int lastReqValid[2] = {0, 0}, lastDrawnValid[2] = {0, 0};
\r
3734 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3737 HBITMAP bufferBitmap;
\r
3738 HBITMAP oldBitmap;
\r
3740 HRGN clips[MAX_CLIPS];
\r
3741 ChessSquare dragged_piece = EmptySquare;
\r
3742 int nr = twoBoards*partnerUp;
\r
3744 /* I'm undecided on this - this function figures out whether a full
\r
3745 * repaint is necessary on its own, so there's no real reason to have the
\r
3746 * caller tell it that. I think this can safely be set to FALSE - but
\r
3747 * if we trust the callers not to request full repaints unnessesarily, then
\r
3748 * we could skip some clipping work. In other words, only request a full
\r
3749 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3750 * gamestart and similar) --Hawk
\r
3752 Boolean fullrepaint = repaint;
\r
3754 if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up
\r
3756 if( DrawPositionNeedsFullRepaint() ) {
\r
3757 fullrepaint = TRUE;
\r
3760 if (board == NULL) {
\r
3761 if (!lastReqValid[nr]) {
\r
3764 board = lastReq[nr];
\r
3766 CopyBoard(lastReq[nr], board);
\r
3767 lastReqValid[nr] = 1;
\r
3770 if (doingSizing) {
\r
3774 if (IsIconic(hwndMain)) {
\r
3778 if (hdc == NULL) {
\r
3779 hdc = GetDC(hwndMain);
\r
3780 if (!appData.monoMode) {
\r
3781 SelectPalette(hdc, hPal, FALSE);
\r
3782 RealizePalette(hdc);
\r
3786 releaseDC = FALSE;
\r
3789 /* Create some work-DCs */
\r
3790 hdcmem = CreateCompatibleDC(hdc);
\r
3791 tmphdc = CreateCompatibleDC(hdc);
\r
3793 /* If dragging is in progress, we temporarely remove the piece */
\r
3794 /* [HGM] or temporarily decrease count if stacked */
\r
3795 /* !! Moved to before board compare !! */
\r
3796 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3797 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3798 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3799 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3800 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3802 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3803 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3804 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3806 board[dragInfo.from.y][dragInfo.from.x] = gatingPiece;
\r
3809 /* Figure out which squares need updating by comparing the
\r
3810 * newest board with the last drawn board and checking if
\r
3811 * flipping has changed.
\r
3813 if (!fullrepaint && lastDrawnValid[nr] && (nr == 1 || lastDrawnFlipView == flipView)) {
\r
3814 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3815 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3816 if (lastDrawn[nr][row][column] != board[row][column]) {
\r
3817 SquareToPos(row, column, &x, &y);
\r
3818 clips[num_clips++] =
\r
3819 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
3823 if(nr == 0) { // [HGM] dual: no highlights on second board
\r
3824 for (i=0; i<2; i++) {
\r
3825 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
3826 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
3827 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
3828 lastDrawnHighlight.sq[i].y >= 0) {
\r
3829 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
3830 lastDrawnHighlight.sq[i].x, &x, &y);
\r
3831 clips[num_clips++] =
\r
3832 CreateRectRgn(x - lineGap, y - lineGap,
\r
3833 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3835 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
3836 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
3837 clips[num_clips++] =
\r
3838 CreateRectRgn(x - lineGap, y - lineGap,
\r
3839 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3843 for (i=0; i<2; i++) {
\r
3844 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
3845 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
3846 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
3847 lastDrawnPremove.sq[i].y >= 0) {
\r
3848 SquareToPos(lastDrawnPremove.sq[i].y,
\r
3849 lastDrawnPremove.sq[i].x, &x, &y);
\r
3850 clips[num_clips++] =
\r
3851 CreateRectRgn(x - lineGap, y - lineGap,
\r
3852 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3854 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3855 premoveHighlightInfo.sq[i].y >= 0) {
\r
3856 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
3857 premoveHighlightInfo.sq[i].x, &x, &y);
\r
3858 clips[num_clips++] =
\r
3859 CreateRectRgn(x - lineGap, y - lineGap,
\r
3860 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3864 } else { // nr == 1
\r
3865 partnerHighlightInfo.sq[0].y = board[EP_STATUS-4];
\r
3866 partnerHighlightInfo.sq[0].x = board[EP_STATUS-3];
\r
3867 partnerHighlightInfo.sq[1].y = board[EP_STATUS-2];
\r
3868 partnerHighlightInfo.sq[1].x = board[EP_STATUS-1];
\r
3869 for (i=0; i<2; i++) {
\r
3870 if (partnerHighlightInfo.sq[i].x >= 0 &&
\r
3871 partnerHighlightInfo.sq[i].y >= 0) {
\r
3872 SquareToPos(partnerHighlightInfo.sq[i].y,
\r
3873 partnerHighlightInfo.sq[i].x, &x, &y);
\r
3874 clips[num_clips++] =
\r
3875 CreateRectRgn(x - lineGap, y - lineGap,
\r
3876 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3878 if (oldPartnerHighlight.sq[i].x >= 0 &&
\r
3879 oldPartnerHighlight.sq[i].y >= 0) {
\r
3880 SquareToPos(oldPartnerHighlight.sq[i].y,
\r
3881 oldPartnerHighlight.sq[i].x, &x, &y);
\r
3882 clips[num_clips++] =
\r
3883 CreateRectRgn(x - lineGap, y - lineGap,
\r
3884 x + squareSize + lineGap, y + squareSize + lineGap);
\r
3889 fullrepaint = TRUE;
\r
3892 /* Create a buffer bitmap - this is the actual bitmap
\r
3893 * being written to. When all the work is done, we can
\r
3894 * copy it to the real DC (the screen). This avoids
\r
3895 * the problems with flickering.
\r
3897 GetClientRect(hwndMain, &Rect);
\r
3898 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
3899 Rect.bottom-Rect.top+1);
\r
3900 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
3901 if (!appData.monoMode) {
\r
3902 SelectPalette(hdcmem, hPal, FALSE);
\r
3905 /* Create clips for dragging */
\r
3906 if (!fullrepaint) {
\r
3907 if (dragInfo.from.x >= 0) {
\r
3908 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
3909 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3911 if (dragInfo.start.x >= 0) {
\r
3912 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
3913 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3915 if (dragInfo.pos.x >= 0) {
\r
3916 x = dragInfo.pos.x - squareSize / 2;
\r
3917 y = dragInfo.pos.y - squareSize / 2;
\r
3918 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3920 if (dragInfo.lastpos.x >= 0) {
\r
3921 x = dragInfo.lastpos.x - squareSize / 2;
\r
3922 y = dragInfo.lastpos.y - squareSize / 2;
\r
3923 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
3927 /* Are we animating a move?
\r
3929 * - remove the piece from the board (temporarely)
\r
3930 * - calculate the clipping region
\r
3932 if (!fullrepaint) {
\r
3933 if (animInfo.piece != EmptySquare) {
\r
3934 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
3935 x = boardRect.left + animInfo.lastpos.x;
\r
3936 y = boardRect.top + animInfo.lastpos.y;
\r
3937 x2 = boardRect.left + animInfo.pos.x;
\r
3938 y2 = boardRect.top + animInfo.pos.y;
\r
3939 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
3940 /* Slight kludge. The real problem is that after AnimateMove is
\r
3941 done, the position on the screen does not match lastDrawn.
\r
3942 This currently causes trouble only on e.p. captures in
\r
3943 atomic, where the piece moves to an empty square and then
\r
3944 explodes. The old and new positions both had an empty square
\r
3945 at the destination, but animation has drawn a piece there and
\r
3946 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
3947 lastDrawn[0][animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
3951 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
3952 if (num_clips == 0)
\r
3953 fullrepaint = TRUE;
\r
3955 /* Set clipping on the memory DC */
\r
3956 if (!fullrepaint) {
\r
3957 SelectClipRgn(hdcmem, clips[0]);
\r
3958 for (x = 1; x < num_clips; x++) {
\r
3959 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
3960 abort(); // this should never ever happen!
\r
3964 /* Do all the drawing to the memory DC */
\r
3965 if(explodeInfo.radius) { // [HGM] atomic
\r
3967 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
3968 ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];
\r
3969 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
3970 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
3971 x += squareSize/2;
\r
3972 y += squareSize/2;
\r
3973 if(!fullrepaint) {
\r
3974 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
3975 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
3977 DrawGridOnDC(hdcmem);
\r
3978 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3979 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3980 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3981 board[explodeInfo.fromY][explodeInfo.fromX] = piece;
\r
3982 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
3983 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
3984 SelectObject(hdcmem, oldBrush);
\r
3986 if(border) DrawBackgroundOnDC(hdcmem);
\r
3987 DrawGridOnDC(hdcmem);
\r
3988 if(nr == 0) { // [HGM] dual: decide which highlights to draw
\r
3989 DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);
\r
3990 DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);
\r
3992 DrawHighlightsOnDC(hdcmem, &partnerHighlightInfo, HIGHLIGHT_PEN);
\r
3993 oldPartnerHighlight = partnerHighlightInfo;
\r
3995 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
3997 if(nr == 0) // [HGM] dual: markers only on left board
\r
3998 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3999 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4000 if (marker[row][column]) { // marker changes only occur with full repaint!
\r
4001 HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);
\r
4002 SquareToPos(row, column, &x, &y);
\r
4003 Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,
\r
4004 x + 3*squareSize/4, y + 3*squareSize/4);
\r
4005 SelectObject(hdcmem, oldBrush);
\r
4010 if( appData.highlightMoveWithArrow ) {
\r
4012 DrawArrowHighlight(hdcmem);
\r
4015 DrawCoordsOnDC(hdcmem);
\r
4017 CopyBoard(lastDrawn[nr], board); /* [HGM] Moved to here from end of routine, */
\r
4018 /* to make sure lastDrawn contains what is actually drawn */
\r
4020 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4021 if (dragged_piece != EmptySquare) {
\r
4022 /* [HGM] or restack */
\r
4023 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4024 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4026 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4027 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4029 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4030 x = dragInfo.pos.x - squareSize / 2;
\r
4031 y = dragInfo.pos.y - squareSize / 2;
\r
4032 DrawPieceOnDC(hdcmem, dragInfo.piece,
\r
4033 ((int) dragInfo.piece < (int) BlackPawn),
\r
4034 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4037 /* Put the animated piece back into place and draw it */
\r
4038 if (animInfo.piece != EmptySquare) {
\r
4039 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4040 x = boardRect.left + animInfo.pos.x;
\r
4041 y = boardRect.top + animInfo.pos.y;
\r
4042 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4043 ((int) animInfo.piece < (int) BlackPawn),
\r
4044 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4047 /* Release the bufferBitmap by selecting in the old bitmap
\r
4048 * and delete the memory DC
\r
4050 SelectObject(hdcmem, oldBitmap);
\r
4053 /* Set clipping on the target DC */
\r
4054 if (!fullrepaint) {
\r
4055 if(nr == 1) for (x = 0; x < num_clips; x++) { // [HGM] dual: translate clips
\r
4057 GetRgnBox(clips[x], &rect);
\r
4058 DeleteObject(clips[x]);
\r
4059 clips[x] = CreateRectRgn(rect.left + wpMain.width/2, rect.top,
\r
4060 rect.right + wpMain.width/2, rect.bottom);
\r
4062 SelectClipRgn(hdc, clips[0]);
\r
4063 for (x = 1; x < num_clips; x++) {
\r
4064 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4065 abort(); // this should never ever happen!
\r
4069 /* Copy the new bitmap onto the screen in one go.
\r
4070 * This way we avoid any flickering
\r
4072 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4073 BitBlt(hdc, boardRect.left + twoBoards*partnerUp*wpMain.width/2, boardRect.top, // [HGM] dual
\r
4074 boardRect.right - boardRect.left,
\r
4075 boardRect.bottom - boardRect.top,
\r
4076 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4077 if(saveDiagFlag) {
\r
4078 BITMAP b; int i, j=0, m, w, wb, fac=0; char *pData;
\r
4079 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4081 GetObject(bufferBitmap, sizeof(b), &b);
\r
4082 if(pData = malloc(b.bmWidthBytes*b.bmHeight + 10000)) {
\r
4083 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4084 bih.biWidth = b.bmWidth;
\r
4085 bih.biHeight = b.bmHeight;
\r
4087 bih.biBitCount = b.bmBitsPixel;
\r
4088 bih.biCompression = 0;
\r
4089 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4090 bih.biXPelsPerMeter = 0;
\r
4091 bih.biYPelsPerMeter = 0;
\r
4092 bih.biClrUsed = 0;
\r
4093 bih.biClrImportant = 0;
\r
4094 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4095 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4096 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4097 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4099 wb = b.bmWidthBytes;
\r
4101 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4102 int k = ((int*) pData)[i];
\r
4103 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4104 if(j >= 16) break;
\r
4106 if(j >= nrColors) nrColors = j+1;
\r
4108 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4110 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4111 for(w=0; w<(wb>>2); w+=2) {
\r
4112 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4113 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4114 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4115 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4116 pData[p++] = m | j<<4;
\r
4118 while(p&3) pData[p++] = 0;
\r
4121 wb = ((wb+31)>>5)<<2;
\r
4123 // write BITMAPFILEHEADER
\r
4124 fprintf(diagFile, "BM");
\r
4125 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4126 fputDW(diagFile, 0);
\r
4127 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4128 // write BITMAPINFOHEADER
\r
4129 fputDW(diagFile, 40);
\r
4130 fputDW(diagFile, b.bmWidth);
\r
4131 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4132 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4133 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4134 fputDW(diagFile, 0);
\r
4135 fputDW(diagFile, 0);
\r
4136 fputDW(diagFile, 0);
\r
4137 fputDW(diagFile, 0);
\r
4138 fputDW(diagFile, 0);
\r
4139 fputDW(diagFile, 0);
\r
4140 // write color table
\r
4142 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4143 // write bitmap data
\r
4144 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4145 fputc(pData[i], diagFile);
\r
4150 SelectObject(tmphdc, oldBitmap);
\r
4152 /* Massive cleanup */
\r
4153 for (x = 0; x < num_clips; x++)
\r
4154 DeleteObject(clips[x]);
\r
4157 DeleteObject(bufferBitmap);
\r
4160 ReleaseDC(hwndMain, hdc);
\r
4162 if (lastDrawnFlipView != flipView && nr == 0) {
\r
4164 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4166 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4169 /* CopyBoard(lastDrawn, board);*/
\r
4170 lastDrawnHighlight = highlightInfo;
\r
4171 lastDrawnPremove = premoveHighlightInfo;
\r
4172 lastDrawnFlipView = flipView;
\r
4173 lastDrawnValid[nr] = 1;
\r
4176 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4181 saveDiagFlag = 1; diagFile = f;
\r
4182 HDCDrawPosition(NULL, TRUE, NULL);
\r
4190 /*---------------------------------------------------------------------------*\
\r
4191 | CLIENT PAINT PROCEDURE
\r
4192 | This is the main event-handler for the WM_PAINT message.
\r
4194 \*---------------------------------------------------------------------------*/
\r
4196 PaintProc(HWND hwnd)
\r
4202 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4203 if (IsIconic(hwnd)) {
\r
4204 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4206 if (!appData.monoMode) {
\r
4207 SelectPalette(hdc, hPal, FALSE);
\r
4208 RealizePalette(hdc);
\r
4210 HDCDrawPosition(hdc, 1, NULL);
\r
4211 if(twoBoards) { // [HGM] dual: also redraw other board in other orientation
\r
4212 flipView = !flipView; partnerUp = !partnerUp;
\r
4213 HDCDrawPosition(hdc, 1, NULL);
\r
4214 flipView = !flipView; partnerUp = !partnerUp;
\r
4217 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4218 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4219 ETO_CLIPPED|ETO_OPAQUE,
\r
4220 &messageRect, messageText, strlen(messageText), NULL);
\r
4221 SelectObject(hdc, oldFont);
\r
4222 DisplayBothClocks();
\r
4225 EndPaint(hwnd,&ps);
\r
4233 * If the user selects on a border boundary, return -1; if off the board,
\r
4234 * return -2. Otherwise map the event coordinate to the square.
\r
4235 * The offset boardRect.left or boardRect.top must already have been
\r
4236 * subtracted from x.
\r
4238 int EventToSquare(x, limit)
\r
4243 if (x < lineGap + border)
\r
4245 x -= lineGap + border;
\r
4246 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4248 x /= (squareSize + lineGap);
\r
4260 DropEnable dropEnables[] = {
\r
4261 { 'P', DP_Pawn, N_("Pawn") },
\r
4262 { 'N', DP_Knight, N_("Knight") },
\r
4263 { 'B', DP_Bishop, N_("Bishop") },
\r
4264 { 'R', DP_Rook, N_("Rook") },
\r
4265 { 'Q', DP_Queen, N_("Queen") },
\r
4269 SetupDropMenu(HMENU hmenu)
\r
4271 int i, count, enable;
\r
4273 extern char white_holding[], black_holding[];
\r
4274 char item[MSG_SIZ];
\r
4276 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4277 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4278 dropEnables[i].piece);
\r
4280 while (p && *p++ == dropEnables[i].piece) count++;
\r
4281 snprintf(item, MSG_SIZ, "%s %d", T_(dropEnables[i].name), count);
\r
4282 enable = count > 0 || !appData.testLegality
\r
4283 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4284 && !appData.icsActive);
\r
4285 ModifyMenu(hmenu, dropEnables[i].command,
\r
4286 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4287 dropEnables[i].command, item);
\r
4291 void DragPieceBegin(int x, int y, Boolean instantly)
\r
4293 dragInfo.lastpos.x = boardRect.left + x;
\r
4294 dragInfo.lastpos.y = boardRect.top + y;
\r
4295 if(instantly) dragInfo.pos = dragInfo.lastpos;
\r
4296 dragInfo.from.x = fromX;
\r
4297 dragInfo.from.y = fromY;
\r
4298 dragInfo.piece = boards[currentMove][fromY][fromX];
\r
4299 dragInfo.start = dragInfo.from;
\r
4300 SetCapture(hwndMain);
\r
4303 void DragPieceEnd(int x, int y)
\r
4306 dragInfo.start.x = dragInfo.start.y = -1;
\r
4307 dragInfo.from = dragInfo.start;
\r
4308 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4311 void ChangeDragPiece(ChessSquare piece)
\r
4313 dragInfo.piece = piece;
\r
4316 /* Event handler for mouse messages */
\r
4318 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4322 static int recursive = 0;
\r
4324 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4327 if (message == WM_MBUTTONUP) {
\r
4328 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4329 to the middle button: we simulate pressing the left button too!
\r
4331 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4332 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4338 pt.x = LOWORD(lParam);
\r
4339 pt.y = HIWORD(lParam);
\r
4340 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4341 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4342 if (!flipView && y >= 0) {
\r
4343 y = BOARD_HEIGHT - 1 - y;
\r
4345 if (flipView && x >= 0) {
\r
4346 x = BOARD_WIDTH - 1 - x;
\r
4349 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
4350 controlKey = GetKeyState(VK_CONTROL) < 0; // [HGM] remember last shift status
\r
4352 switch (message) {
\r
4353 case WM_LBUTTONDOWN:
\r
4354 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4355 ClockClick(flipClock); break;
\r
4356 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4357 ClockClick(!flipClock); break;
\r
4359 if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging
\r
4360 dragInfo.start.x = dragInfo.start.y = -1;
\r
4361 dragInfo.from = dragInfo.start;
\r
4363 if(fromX == -1 && frozen) { // not sure where this is for
\r
4364 fromX = fromY = -1;
\r
4365 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4368 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4369 DrawPosition(TRUE, NULL);
\r
4372 case WM_LBUTTONUP:
\r
4373 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4374 DrawPosition(TRUE, NULL);
\r
4377 case WM_MOUSEMOVE:
\r
4378 if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, 1)) break;
\r
4379 if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;
\r
4380 MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);
\r
4381 if ((appData.animateDragging || appData.highlightDragging)
\r
4382 && (wParam & MK_LBUTTON || dragging == 2)
\r
4383 && dragInfo.from.x >= 0)
\r
4385 BOOL full_repaint = FALSE;
\r
4387 if (appData.animateDragging) {
\r
4388 dragInfo.pos = pt;
\r
4390 if (appData.highlightDragging) {
\r
4391 HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);
\r
4392 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4393 full_repaint = TRUE;
\r
4397 DrawPosition( full_repaint, NULL);
\r
4399 dragInfo.lastpos = dragInfo.pos;
\r
4403 case WM_MOUSEWHEEL: // [DM]
\r
4404 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4405 /* Mouse Wheel is being rolled forward
\r
4406 * Play moves forward
\r
4408 if((short)HIWORD(wParam) < 0 && currentMove < forwardMostMove)
\r
4409 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4410 /* Mouse Wheel is being rolled backward
\r
4411 * Play moves backward
\r
4413 if((short)HIWORD(wParam) > 0 && currentMove > backwardMostMove)
\r
4414 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4418 case WM_MBUTTONUP:
\r
4419 case WM_RBUTTONUP:
\r
4421 RightClick(Release, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4424 case WM_MBUTTONDOWN:
\r
4425 case WM_RBUTTONDOWN:
\r
4428 fromX = fromY = -1;
\r
4429 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4430 dragInfo.start.x = dragInfo.start.y = -1;
\r
4431 dragInfo.from = dragInfo.start;
\r
4432 dragInfo.lastpos = dragInfo.pos;
\r
4433 if (appData.highlightDragging) {
\r
4434 ClearHighlights();
\r
4437 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4438 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4439 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(flipClock, 1);
\r
4440 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4441 if (GetKeyState(VK_SHIFT) < 0) AdjustClock(!flipClock, 1);
\r
4445 DrawPosition(TRUE, NULL);
\r
4447 menuNr = RightClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, &fromX, &fromY);
\r
4450 if (message == WM_MBUTTONDOWN) {
\r
4451 buttonCount = 3; /* even if system didn't think so */
\r
4452 if (wParam & MK_SHIFT)
\r
4453 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4455 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4456 } else { /* message == WM_RBUTTONDOWN */
\r
4457 /* Just have one menu, on the right button. Windows users don't
\r
4458 think to try the middle one, and sometimes other software steals
\r
4459 it, or it doesn't really exist. */
\r
4460 if(gameInfo.variant != VariantShogi)
\r
4461 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4463 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4467 SetCapture(hwndMain);
\r
4470 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4471 SetupDropMenu(hmenu);
\r
4472 MenuPopup(hwnd, pt, hmenu, -1);
\r
4482 /* Preprocess messages for buttons in main window */
\r
4484 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4486 int id = GetWindowLongPtr(hwnd, GWLP_ID);
\r
4489 for (i=0; i<N_BUTTONS; i++) {
\r
4490 if (buttonDesc[i].id == id) break;
\r
4492 if (i == N_BUTTONS) return 0;
\r
4493 switch (message) {
\r
4498 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4499 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4506 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4509 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4510 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4511 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4512 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4514 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4516 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4517 TypeInEvent((char)wParam);
\r
4523 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4526 static int promoStyle;
\r
4528 /* Process messages for Promotion dialog box */
\r
4530 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4535 switch (message) {
\r
4537 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4538 /* Center the dialog over the application window */
\r
4539 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4540 Translate(hDlg, DLG_PromotionKing);
\r
4541 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4542 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4543 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
\r
4544 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4545 SW_SHOW : SW_HIDE);
\r
4546 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4547 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4548 ((PieceToChar(WhiteAngel) >= 'A' && WhiteOnMove(currentMove) &&
\r
4549 PieceToChar(WhiteAngel) != '~') ||
\r
4550 (PieceToChar(BlackAngel) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4551 PieceToChar(BlackAngel) != '~') ) ?
\r
4552 SW_SHOW : SW_HIDE);
\r
4553 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4554 ((PieceToChar(WhiteMarshall) >= 'A' && WhiteOnMove(currentMove) &&
\r
4555 PieceToChar(WhiteMarshall) != '~') ||
\r
4556 (PieceToChar(BlackMarshall) >= 'A' && !WhiteOnMove(currentMove) &&
\r
4557 PieceToChar(BlackMarshall) != '~') ) ?
\r
4558 SW_SHOW : SW_HIDE);
\r
4559 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4560 ShowWindow(GetDlgItem(hDlg, PB_Rook), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4561 ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);
\r
4563 SetDlgItemText(hDlg, PB_Queen, "YES");
\r
4564 SetDlgItemText(hDlg, PB_Knight, "NO");
\r
4565 SetWindowText(hDlg, "Promote?");
\r
4567 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4568 gameInfo.variant == VariantSuper ?
\r
4569 SW_SHOW : SW_HIDE);
\r
4572 case WM_COMMAND: /* message: received a command */
\r
4573 switch (LOWORD(wParam)) {
\r
4575 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4576 ClearHighlights();
\r
4577 DrawPosition(FALSE, NULL);
\r
4580 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4583 promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));
\r
4586 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));
\r
4587 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackDragon);
\r
4590 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteBishop : BlackBishop));
\r
4591 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) promoChar = PieceToChar(BlackAlfil);
\r
4593 case PB_Chancellor:
\r
4594 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteMarshall : BlackMarshall));
\r
4596 case PB_Archbishop:
\r
4597 promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));
\r
4600 promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR :
\r
4601 ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));
\r
4606 if(promoChar == '.') return FALSE; // invalid piece chosen
\r
4607 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4608 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
4609 fromX = fromY = -1;
\r
4610 if (!appData.highlightLastMove) {
\r
4611 ClearHighlights();
\r
4612 DrawPosition(FALSE, NULL);
\r
4619 /* Pop up promotion dialog */
\r
4621 PromotionPopup(HWND hwnd)
\r
4625 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4626 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4627 hwnd, (DLGPROC)lpProc);
\r
4628 FreeProcInstance(lpProc);
\r
4632 PromotionPopUp(char choice)
\r
4634 promoStyle = (choice == '+' || IS_SHOGI(gameInfo.variant));
\r
4635 DrawPosition(TRUE, NULL);
\r
4636 PromotionPopup(hwndMain);
\r
4640 LoadGameDialog(HWND hwnd, char* title)
\r
4644 char fileTitle[MSG_SIZ];
\r
4645 f = OpenFileDialog(hwnd, "rb", "",
\r
4646 appData.oldSaveStyle ? "gam" : "pgn",
\r
4648 title, &number, fileTitle, NULL);
\r
4650 cmailMsgLoaded = FALSE;
\r
4651 if (number == 0) {
\r
4652 int error = GameListBuild(f);
\r
4654 DisplayError(_("Cannot build game list"), error);
\r
4655 } else if (!ListEmpty(&gameList) &&
\r
4656 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4657 GameListPopUp(f, fileTitle);
\r
4660 GameListDestroy();
\r
4663 LoadGame(f, number, fileTitle, FALSE);
\r
4667 int get_term_width()
\r
4672 HFONT hfont, hold_font;
\r
4677 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4681 // get the text metrics
\r
4682 hdc = GetDC(hText);
\r
4683 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
4684 if (consoleCF.dwEffects & CFE_BOLD)
\r
4685 lf.lfWeight = FW_BOLD;
\r
4686 if (consoleCF.dwEffects & CFE_ITALIC)
\r
4687 lf.lfItalic = TRUE;
\r
4688 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
4689 lf.lfStrikeOut = TRUE;
\r
4690 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
4691 lf.lfUnderline = TRUE;
\r
4692 hfont = CreateFontIndirect(&lf);
\r
4693 hold_font = SelectObject(hdc, hfont);
\r
4694 GetTextMetrics(hdc, &tm);
\r
4695 SelectObject(hdc, hold_font);
\r
4696 DeleteObject(hfont);
\r
4697 ReleaseDC(hText, hdc);
\r
4699 // get the rectangle
\r
4700 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
4702 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
4705 void UpdateICSWidth(HWND hText)
\r
4707 LONG old_width, new_width;
\r
4709 new_width = get_term_width(hText, FALSE);
\r
4710 old_width = GetWindowLongPtr(hText, GWLP_USERDATA);
\r
4711 if (new_width != old_width)
\r
4713 ics_update_width(new_width);
\r
4714 SetWindowLongPtr(hText, GWLP_USERDATA, new_width);
\r
4719 ChangedConsoleFont()
\r
4722 CHARRANGE tmpsel, sel;
\r
4723 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4724 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4725 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4728 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4729 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4730 safeStrCpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName,
\r
4731 sizeof(cfmt.szFaceName)/sizeof(cfmt.szFaceName[0]) );
\r
4732 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4733 * size. This was undocumented in the version of MSVC++ that I had
\r
4734 * when I wrote the code, but is apparently documented now.
\r
4736 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4737 cfmt.bCharSet = f->lf.lfCharSet;
\r
4738 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4739 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4740 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4741 /* Why are the following seemingly needed too? */
\r
4742 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4743 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4744 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4746 tmpsel.cpMax = -1; /*999999?*/
\r
4747 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4748 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4749 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4750 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4752 paraf.cbSize = sizeof(paraf);
\r
4753 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4754 paraf.dxStartIndent = 0;
\r
4755 paraf.dxOffset = WRAP_INDENT;
\r
4756 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4757 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4758 UpdateICSWidth(hText);
\r
4761 /*---------------------------------------------------------------------------*\
\r
4763 * Window Proc for main window
\r
4765 \*---------------------------------------------------------------------------*/
\r
4767 /* Process messages for main window, etc. */
\r
4769 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4776 char fileTitle[MSG_SIZ];
\r
4777 static SnapData sd;
\r
4778 static int peek=0;
\r
4780 switch (message) {
\r
4782 case WM_PAINT: /* message: repaint portion of window */
\r
4786 case WM_ERASEBKGND:
\r
4787 if (IsIconic(hwnd)) {
\r
4788 /* Cheat; change the message */
\r
4789 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4791 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4795 case WM_LBUTTONDOWN:
\r
4796 case WM_MBUTTONDOWN:
\r
4797 case WM_RBUTTONDOWN:
\r
4798 case WM_LBUTTONUP:
\r
4799 case WM_MBUTTONUP:
\r
4800 case WM_RBUTTONUP:
\r
4801 case WM_MOUSEMOVE:
\r
4802 case WM_MOUSEWHEEL:
\r
4803 MouseEvent(hwnd, message, wParam, lParam);
\r
4807 if((char)wParam == '\b') {
\r
4808 ForwardEvent(); peek = 0;
\r
4811 JAWS_KBUP_NAVIGATION
\r
4816 if((char)wParam == '\b') {
\r
4817 if(!peek) BackwardEvent(), peek = 1;
\r
4820 JAWS_KBDOWN_NAVIGATION
\r
4826 JAWS_ALT_INTERCEPT
\r
4828 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
4829 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
4830 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4831 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4833 SendMessage(h, message, wParam, lParam);
\r
4834 } else if(lParam != KF_REPEAT) {
\r
4835 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4836 TypeInEvent((char)wParam);
\r
4837 } else if((char)wParam == 003) CopyGameToClipboard();
\r
4838 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
4843 case WM_PALETTECHANGED:
\r
4844 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4846 HDC hdc = GetDC(hwndMain);
\r
4847 SelectPalette(hdc, hPal, TRUE);
\r
4848 nnew = RealizePalette(hdc);
\r
4850 paletteChanged = TRUE;
\r
4852 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4854 ReleaseDC(hwnd, hdc);
\r
4858 case WM_QUERYNEWPALETTE:
\r
4859 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4861 HDC hdc = GetDC(hwndMain);
\r
4862 paletteChanged = FALSE;
\r
4863 SelectPalette(hdc, hPal, FALSE);
\r
4864 nnew = RealizePalette(hdc);
\r
4866 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4868 ReleaseDC(hwnd, hdc);
\r
4873 case WM_COMMAND: /* message: command from application menu */
\r
4874 wmId = LOWORD(wParam);
\r
4879 SAY("new game enter a move to play against the computer with white");
\r
4882 case IDM_NewGameFRC:
\r
4883 if( NewGameFRC() == 0 ) {
\r
4888 case IDM_NewVariant:
\r
4889 NewVariantPopup(hwnd);
\r
4892 case IDM_LoadGame:
\r
4893 LoadGameDialog(hwnd, _("Load Game from File"));
\r
4896 case IDM_LoadNextGame:
\r
4900 case IDM_LoadPrevGame:
\r
4904 case IDM_ReloadGame:
\r
4908 case IDM_LoadPosition:
\r
4909 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4910 Reset(FALSE, TRUE);
\r
4913 f = OpenFileDialog(hwnd, "rb", "",
\r
4914 appData.oldSaveStyle ? "pos" : "fen",
\r
4916 _("Load Position from File"), &number, fileTitle, NULL);
\r
4918 LoadPosition(f, number, fileTitle);
\r
4922 case IDM_LoadNextPosition:
\r
4923 ReloadPosition(1);
\r
4926 case IDM_LoadPrevPosition:
\r
4927 ReloadPosition(-1);
\r
4930 case IDM_ReloadPosition:
\r
4931 ReloadPosition(0);
\r
4934 case IDM_SaveGame:
\r
4935 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4936 f = OpenFileDialog(hwnd, "a", defName,
\r
4937 appData.oldSaveStyle ? "gam" : "pgn",
\r
4939 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4941 SaveGame(f, 0, "");
\r
4945 case IDM_SavePosition:
\r
4946 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
4947 f = OpenFileDialog(hwnd, "a", defName,
\r
4948 appData.oldSaveStyle ? "pos" : "fen",
\r
4950 _("Save Position to File"), NULL, fileTitle, NULL);
\r
4952 SavePosition(f, 0, "");
\r
4956 case IDM_SaveDiagram:
\r
4957 defName = "diagram";
\r
4958 f = OpenFileDialog(hwnd, "wb", defName,
\r
4961 _("Save Diagram to File"), NULL, fileTitle, NULL);
\r
4967 case IDM_SaveSelected:
\r
4968 f = OpenFileDialog(hwnd, "a", "",
\r
4971 _("Save Game to File"), NULL, fileTitle, NULL);
\r
4973 SaveSelected(f, 0, "");
\r
4977 case IDM_CreateBook:
\r
4978 CreateBookEvent();
\r
4981 case IDM_CopyGame:
\r
4982 CopyGameToClipboard();
\r
4985 case IDM_PasteGame:
\r
4986 PasteGameFromClipboard();
\r
4989 case IDM_CopyGameListToClipboard:
\r
4990 CopyGameListToClipboard();
\r
4993 /* [AS] Autodetect FEN or PGN data */
\r
4994 case IDM_PasteAny:
\r
4995 PasteGameOrFENFromClipboard();
\r
4998 /* [AS] Move history */
\r
4999 case IDM_ShowMoveHistory:
\r
5000 if( MoveHistoryIsUp() ) {
\r
5001 MoveHistoryPopDown();
\r
5004 MoveHistoryPopUp();
\r
5008 /* [AS] Eval graph */
\r
5009 case IDM_ShowEvalGraph:
\r
5010 if( EvalGraphIsUp() ) {
\r
5011 EvalGraphPopDown();
\r
5015 SetFocus(hwndMain);
\r
5019 /* [AS] Engine output */
\r
5020 case IDM_ShowEngineOutput:
\r
5021 if( EngineOutputIsUp() ) {
\r
5022 EngineOutputPopDown();
\r
5025 EngineOutputPopUp();
\r
5029 /* [AS] User adjudication */
\r
5030 case IDM_UserAdjudication_White:
\r
5031 UserAdjudicationEvent( +1 );
\r
5034 case IDM_UserAdjudication_Black:
\r
5035 UserAdjudicationEvent( -1 );
\r
5038 case IDM_UserAdjudication_Draw:
\r
5039 UserAdjudicationEvent( 0 );
\r
5042 /* [AS] Game list options dialog */
\r
5043 case IDM_GameListOptions:
\r
5044 GameListOptions();
\r
5051 case IDM_CopyPosition:
\r
5052 CopyFENToClipboard();
\r
5055 case IDM_PastePosition:
\r
5056 PasteFENFromClipboard();
\r
5059 case IDM_MailMove:
\r
5063 case IDM_ReloadCMailMsg:
\r
5064 Reset(TRUE, TRUE);
\r
5065 ReloadCmailMsgEvent(FALSE);
\r
5068 case IDM_Minimize:
\r
5069 ShowWindow(hwnd, SW_MINIMIZE);
\r
5076 case IDM_MachineWhite:
\r
5077 MachineWhiteEvent();
\r
5079 * refresh the tags dialog only if it's visible
\r
5081 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5083 tags = PGNTags(&gameInfo);
\r
5084 TagsPopUp(tags, CmailMsg());
\r
5087 SAY("computer starts playing white");
\r
5090 case IDM_MachineBlack:
\r
5091 MachineBlackEvent();
\r
5093 * refresh the tags dialog only if it's visible
\r
5095 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5097 tags = PGNTags(&gameInfo);
\r
5098 TagsPopUp(tags, CmailMsg());
\r
5101 SAY("computer starts playing black");
\r
5104 case IDM_Match: // [HGM] match: flows into next case, after setting Match Mode and nr of Games
\r
5105 if(matchMode) EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_GRAYED);
\r
5106 MatchEvent(2); // distinguish from command-line-triggered case (matchMode=1)
\r
5109 case IDM_TwoMachines:
\r
5110 TwoMachinesEvent();
\r
5113 * refresh the tags dialog only if it's visible
\r
5115 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5117 tags = PGNTags(&gameInfo);
\r
5118 TagsPopUp(tags, CmailMsg());
\r
5121 SAY("computer starts playing both sides");
\r
5124 case IDM_AnalysisMode:
\r
5125 if(AnalyzeModeEvent()) {
\r
5126 SAY("analyzing current position");
\r
5130 case IDM_AnalyzeFile:
\r
5131 AnalyzeFileEvent();
\r
5134 case IDM_IcsClient:
\r
5138 case IDM_EditGame:
\r
5139 case IDM_EditGame2:
\r
5144 case IDM_EditPosition:
\r
5145 case IDM_EditPosition2:
\r
5146 EditPositionEvent();
\r
5147 SAY("enter a FEN string or setup a position on the board using the control R pop up menu");
\r
5150 case IDM_Training:
\r
5154 case IDM_ShowGameList:
\r
5155 ShowGameListProc();
\r
5158 case IDM_EditProgs1:
\r
5159 EditTagsPopUp(firstChessProgramNames, &firstChessProgramNames);
\r
5162 case IDM_LoadProg1:
\r
5163 LoadEnginePopUp(hwndMain, 0);
\r
5166 case IDM_LoadProg2:
\r
5167 LoadEnginePopUp(hwndMain, 1);
\r
5170 case IDM_EditServers:
\r
5171 EditTagsPopUp(icsNames, &icsNames);
\r
5174 case IDM_EditTags:
\r
5179 case IDM_EditBook:
\r
5183 case IDM_EditComment:
\r
5185 if (commentUp && editComment) {
\r
5188 EditCommentEvent();
\r
5209 case IDM_CallFlag:
\r
5229 case IDM_StopObserving:
\r
5230 StopObservingEvent();
\r
5233 case IDM_StopExamining:
\r
5234 StopExaminingEvent();
\r
5238 UploadGameEvent();
\r
5241 case IDM_TypeInMove:
\r
5242 TypeInEvent('\000');
\r
5245 case IDM_TypeInName:
\r
5246 PopUpNameDialog('\000');
\r
5249 case IDM_Backward:
\r
5251 SetFocus(hwndMain);
\r
5258 SetFocus(hwndMain);
\r
5263 SetFocus(hwndMain);
\r
5268 SetFocus(hwndMain);
\r
5271 case OPT_GameListNext: // [HGM] forward these two accelerators to Game List
\r
5272 case OPT_GameListPrev:
\r
5273 if(gameListDialog) SendMessage(gameListDialog, WM_COMMAND, wmId, 0);
\r
5277 RevertEvent(FALSE);
\r
5280 case IDM_Annotate: // [HGM] vari: revert with annotation
\r
5281 RevertEvent(TRUE);
\r
5284 case IDM_TruncateGame:
\r
5285 TruncateGameEvent();
\r
5292 case IDM_RetractMove:
\r
5293 RetractMoveEvent();
\r
5296 case IDM_FlipView:
\r
5297 flipView = !flipView;
\r
5298 DrawPosition(FALSE, NULL);
\r
5301 case IDM_FlipClock:
\r
5302 flipClock = !flipClock;
\r
5303 DisplayBothClocks();
\r
5307 case IDM_MuteSounds:
\r
5308 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5309 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5310 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5313 case IDM_GeneralOptions:
\r
5314 GeneralOptionsPopup(hwnd);
\r
5315 DrawPosition(TRUE, NULL);
\r
5318 case IDM_BoardOptions:
\r
5319 BoardOptionsPopup(hwnd);
\r
5322 case IDM_ThemeOptions:
\r
5323 ThemeOptionsPopup(hwnd);
\r
5326 case IDM_EnginePlayOptions:
\r
5327 EnginePlayOptionsPopup(hwnd);
\r
5330 case IDM_Engine1Options:
\r
5331 EngineOptionsPopup(hwnd, &first);
\r
5334 case IDM_Engine2Options:
\r
5336 if(WaitForEngine(&second, SettingsMenuIfReady)) break;
\r
5337 EngineOptionsPopup(hwnd, &second);
\r
5340 case IDM_OptionsUCI:
\r
5341 UciOptionsPopup(hwnd);
\r
5345 TourneyPopup(hwnd);
\r
5348 case IDM_IcsOptions:
\r
5349 IcsOptionsPopup(hwnd);
\r
5353 FontsOptionsPopup(hwnd);
\r
5357 SoundOptionsPopup(hwnd);
\r
5360 case IDM_CommPort:
\r
5361 CommPortOptionsPopup(hwnd);
\r
5364 case IDM_LoadOptions:
\r
5365 LoadOptionsPopup(hwnd);
\r
5368 case IDM_SaveOptions:
\r
5369 SaveOptionsPopup(hwnd);
\r
5372 case IDM_TimeControl:
\r
5373 TimeControlOptionsPopup(hwnd);
\r
5376 case IDM_SaveSettings:
\r
5377 SaveSettings(settingsFileName);
\r
5380 case IDM_SaveSettingsOnExit:
\r
5381 saveSettingsOnExit = !saveSettingsOnExit;
\r
5382 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5383 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5384 MF_CHECKED : MF_UNCHECKED));
\r
5395 case IDM_AboutGame:
\r
5400 appData.debugMode = !appData.debugMode;
\r
5401 if (appData.debugMode) {
\r
5402 char dir[MSG_SIZ];
\r
5403 GetCurrentDirectory(MSG_SIZ, dir);
\r
5404 SetCurrentDirectory(installDir);
\r
5405 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5406 SetCurrentDirectory(dir);
\r
5407 setbuf(debugFP, NULL);
\r
5414 case IDM_HELPCONTENTS:
\r
5415 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5416 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5417 MessageBox (GetFocus(),
\r
5418 _("Unable to activate help"),
\r
5419 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5423 case IDM_HELPSEARCH:
\r
5424 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5425 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5426 MessageBox (GetFocus(),
\r
5427 _("Unable to activate help"),
\r
5428 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5432 case IDM_HELPHELP:
\r
5433 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5434 MessageBox (GetFocus(),
\r
5435 _("Unable to activate help"),
\r
5436 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5441 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5443 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5444 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5445 FreeProcInstance(lpProc);
\r
5448 case IDM_DirectCommand1:
\r
5449 AskQuestionEvent(_("Direct Command"),
\r
5450 _("Send to chess program:"), "", "1");
\r
5452 case IDM_DirectCommand2:
\r
5453 AskQuestionEvent(_("Direct Command"),
\r
5454 _("Send to second chess program:"), "", "2");
\r
5457 case EP_WhitePawn:
\r
5458 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5459 fromX = fromY = -1;
\r
5462 case EP_WhiteKnight:
\r
5463 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5464 fromX = fromY = -1;
\r
5467 case EP_WhiteBishop:
\r
5468 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5469 fromX = fromY = -1;
\r
5472 case EP_WhiteRook:
\r
5473 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5474 fromX = fromY = -1;
\r
5477 case EP_WhiteQueen:
\r
5478 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5479 fromX = fromY = -1;
\r
5482 case EP_WhiteFerz:
\r
5483 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5484 fromX = fromY = -1;
\r
5487 case EP_WhiteWazir:
\r
5488 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5489 fromX = fromY = -1;
\r
5492 case EP_WhiteAlfil:
\r
5493 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5494 fromX = fromY = -1;
\r
5497 case EP_WhiteCannon:
\r
5498 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5499 fromX = fromY = -1;
\r
5502 case EP_WhiteCardinal:
\r
5503 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5504 fromX = fromY = -1;
\r
5507 case EP_WhiteMarshall:
\r
5508 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5509 fromX = fromY = -1;
\r
5512 case EP_WhiteKing:
\r
5513 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5514 fromX = fromY = -1;
\r
5517 case EP_BlackPawn:
\r
5518 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5519 fromX = fromY = -1;
\r
5522 case EP_BlackKnight:
\r
5523 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5524 fromX = fromY = -1;
\r
5527 case EP_BlackBishop:
\r
5528 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5529 fromX = fromY = -1;
\r
5532 case EP_BlackRook:
\r
5533 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5534 fromX = fromY = -1;
\r
5537 case EP_BlackQueen:
\r
5538 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5539 fromX = fromY = -1;
\r
5542 case EP_BlackFerz:
\r
5543 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5544 fromX = fromY = -1;
\r
5547 case EP_BlackWazir:
\r
5548 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5549 fromX = fromY = -1;
\r
5552 case EP_BlackAlfil:
\r
5553 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5554 fromX = fromY = -1;
\r
5557 case EP_BlackCannon:
\r
5558 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5559 fromX = fromY = -1;
\r
5562 case EP_BlackCardinal:
\r
5563 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5564 fromX = fromY = -1;
\r
5567 case EP_BlackMarshall:
\r
5568 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5569 fromX = fromY = -1;
\r
5572 case EP_BlackKing:
\r
5573 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5574 fromX = fromY = -1;
\r
5577 case EP_EmptySquare:
\r
5578 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5579 fromX = fromY = -1;
\r
5582 case EP_ClearBoard:
\r
5583 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5584 fromX = fromY = -1;
\r
5588 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5589 fromX = fromY = -1;
\r
5593 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5594 fromX = fromY = -1;
\r
5598 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5599 fromX = fromY = -1;
\r
5603 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5604 fromX = fromY = -1;
\r
5608 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5609 fromX = fromY = -1;
\r
5613 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5614 fromX = fromY = -1;
\r
5618 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5619 fromX = fromY = -1;
\r
5623 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5624 fromX = fromY = -1;
\r
5628 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5629 fromX = fromY = -1;
\r
5633 barbaric = 0; appData.language = "";
\r
5634 TranslateMenus(0);
\r
5635 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5636 CheckMenuItem(GetMenu(hwndMain), IDM_English, MF_BYCOMMAND|MF_CHECKED);
\r
5637 lastChecked = wmId;
\r
5641 if(wmId >= IDM_RecentEngines && wmId < IDM_RecentEngines + appData.recentEngines)
\r
5642 RecentEngineEvent(wmId - IDM_RecentEngines);
\r
5644 if(wmId > IDM_English && wmId < IDM_English+20) {
\r
5645 LoadLanguageFile(languageFile[wmId - IDM_English - 1]);
\r
5646 TranslateMenus(0);
\r
5647 CheckMenuItem(GetMenu(hwndMain), lastChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
5648 CheckMenuItem(GetMenu(hwndMain), wmId, MF_BYCOMMAND|MF_CHECKED);
\r
5649 lastChecked = wmId;
\r
5652 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5658 case CLOCK_TIMER_ID:
\r
5659 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5660 clockTimerEvent = 0;
\r
5661 DecrementClocks(); /* call into back end */
\r
5663 case LOAD_GAME_TIMER_ID:
\r
5664 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5665 loadGameTimerEvent = 0;
\r
5666 AutoPlayGameLoop(); /* call into back end */
\r
5668 case ANALYSIS_TIMER_ID:
\r
5669 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
5670 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
5671 AnalysisPeriodicEvent(0);
\r
5673 KillTimer(hwnd, analysisTimerEvent);
\r
5674 analysisTimerEvent = 0;
\r
5677 case DELAYED_TIMER_ID:
\r
5678 KillTimer(hwnd, delayedTimerEvent);
\r
5679 delayedTimerEvent = 0;
\r
5680 delayedTimerCallback();
\r
5685 case WM_USER_Input:
\r
5686 InputEvent(hwnd, message, wParam, lParam);
\r
5689 /* [AS] Also move "attached" child windows */
\r
5690 case WM_WINDOWPOSCHANGING:
\r
5692 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5693 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5695 if( ((lpwp->flags & SWP_NOMOVE) == 0) /*&& ((lpwp->flags & SWP_NOSIZE) != 0)*/ ) { // [HGM] in Win8 size always accompanies move?
\r
5696 /* Window is moving */
\r
5699 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
5700 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
5701 rcMain.right = wpMain.x + wpMain.width;
\r
5702 rcMain.top = wpMain.y;
\r
5703 rcMain.bottom = wpMain.y + wpMain.height;
\r
5705 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5706 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5707 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5708 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
5709 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
5710 wpMain.x = lpwp->x;
\r
5711 wpMain.y = lpwp->y;
\r
5716 /* [AS] Snapping */
\r
5717 case WM_ENTERSIZEMOVE:
\r
5718 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
5719 if (hwnd == hwndMain) {
\r
5720 doingSizing = TRUE;
\r
5723 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5727 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
5728 if (hwnd == hwndMain) {
\r
5729 lastSizing = wParam;
\r
5734 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
5735 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5737 case WM_EXITSIZEMOVE:
\r
5738 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
5739 if (hwnd == hwndMain) {
\r
5741 doingSizing = FALSE;
\r
5742 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5743 GetClientRect(hwnd, &client);
\r
5744 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5746 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
5748 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5751 case WM_DESTROY: /* message: window being destroyed */
\r
5752 PostQuitMessage(0);
\r
5756 if (hwnd == hwndMain) {
\r
5761 default: /* Passes it on if unprocessed */
\r
5762 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5769 /*---------------------------------------------------------------------------*\
\r
5771 * Misc utility routines
\r
5773 \*---------------------------------------------------------------------------*/
\r
5776 * Decent random number generator, at least not as bad as Windows
\r
5777 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5779 unsigned int randstate;
\r
5784 randstate = randstate * 1664525 + 1013904223;
\r
5785 return (int) randstate & 0x7fffffff;
\r
5789 mysrandom(unsigned int seed)
\r
5796 * returns TRUE if user selects a different color, FALSE otherwise
\r
5800 ChangeColor(HWND hwnd, COLORREF *which)
\r
5802 static BOOL firstTime = TRUE;
\r
5803 static DWORD customColors[16];
\r
5805 COLORREF newcolor;
\r
5810 /* Make initial colors in use available as custom colors */
\r
5811 /* Should we put the compiled-in defaults here instead? */
\r
5813 customColors[i++] = lightSquareColor & 0xffffff;
\r
5814 customColors[i++] = darkSquareColor & 0xffffff;
\r
5815 customColors[i++] = whitePieceColor & 0xffffff;
\r
5816 customColors[i++] = blackPieceColor & 0xffffff;
\r
5817 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5818 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5820 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5821 customColors[i++] = textAttribs[ccl].color;
\r
5823 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5824 firstTime = FALSE;
\r
5827 cc.lStructSize = sizeof(cc);
\r
5828 cc.hwndOwner = hwnd;
\r
5829 cc.hInstance = NULL;
\r
5830 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5831 cc.lpCustColors = (LPDWORD) customColors;
\r
5832 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5834 if (!ChooseColor(&cc)) return FALSE;
\r
5836 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5837 if (newcolor == *which) return FALSE;
\r
5838 *which = newcolor;
\r
5842 InitDrawingColors();
\r
5843 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5848 MyLoadSound(MySound *ms)
\r
5854 if (ms->data && ms->flag) free(ms->data);
\r
5857 switch (ms->name[0]) {
\r
5863 /* System sound from Control Panel. Don't preload here. */
\r
5867 if (ms->name[1] == NULLCHAR) {
\r
5868 /* "!" alone = silence */
\r
5871 /* Builtin wave resource. Error if not found. */
\r
5872 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5873 if (h == NULL) break;
\r
5874 ms->data = (void *)LoadResource(hInst, h);
\r
5875 ms->flag = 0; // not maloced, so cannot be freed!
\r
5876 if (h == NULL) break;
\r
5881 /* .wav file. Error if not found. */
\r
5882 f = fopen(ms->name, "rb");
\r
5883 if (f == NULL) break;
\r
5884 if (fstat(fileno(f), &st) < 0) break;
\r
5885 ms->data = malloc(st.st_size);
\r
5887 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5893 char buf[MSG_SIZ];
\r
5894 snprintf(buf, MSG_SIZ, _("Error loading sound %s"), ms->name);
\r
5895 DisplayError(buf, GetLastError());
\r
5901 MyPlaySound(MySound *ms)
\r
5903 BOOLEAN ok = FALSE;
\r
5905 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
5906 switch (ms->name[0]) {
\r
5908 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
5913 /* System sound from Control Panel (deprecated feature).
\r
5914 "$" alone or an unset sound name gets default beep (still in use). */
\r
5915 if (ms->name[1]) {
\r
5916 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5918 if (!ok) ok = MessageBeep(MB_OK);
\r
5921 /* Builtin wave resource, or "!" alone for silence */
\r
5922 if (ms->name[1]) {
\r
5923 if (ms->data == NULL) return FALSE;
\r
5924 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5930 /* .wav file. Error if not found. */
\r
5931 if (ms->data == NULL) return FALSE;
\r
5932 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5935 /* Don't print an error: this can happen innocently if the sound driver
\r
5936 is busy; for instance, if another instance of WinBoard is playing
\r
5937 a sound at about the same time. */
\r
5943 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5946 OPENFILENAME *ofn;
\r
5947 static UINT *number; /* gross that this is static */
\r
5949 switch (message) {
\r
5950 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5951 /* Center the dialog over the application window */
\r
5952 ofn = (OPENFILENAME *) lParam;
\r
5953 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5954 number = (UINT *) ofn->lCustData;
\r
5955 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5959 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5960 Translate(hDlg, 1536);
\r
5961 return FALSE; /* Allow for further processing */
\r
5964 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5965 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5967 return FALSE; /* Allow for further processing */
\r
5973 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5975 static UINT *number;
\r
5976 OPENFILENAME *ofname;
\r
5979 case WM_INITDIALOG:
\r
5980 Translate(hdlg, DLG_IndexNumber);
\r
5981 ofname = (OPENFILENAME *)lParam;
\r
5982 number = (UINT *)(ofname->lCustData);
\r
5985 ofnot = (OFNOTIFY *)lParam;
\r
5986 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5987 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5996 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
5997 char *nameFilt, char *dlgTitle, UINT *number,
\r
5998 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6000 OPENFILENAME openFileName;
\r
6001 char buf1[MSG_SIZ];
\r
6004 if (fileName == NULL) fileName = buf1;
\r
6005 if (defName == NULL) {
\r
6006 safeStrCpy(fileName, "*.", 3 );
\r
6007 strcat(fileName, defExt);
\r
6009 safeStrCpy(fileName, defName, MSG_SIZ );
\r
6011 if (fileTitle) safeStrCpy(fileTitle, "", MSG_SIZ );
\r
6012 if (number) *number = 0;
\r
6014 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6015 openFileName.hwndOwner = hwnd;
\r
6016 openFileName.hInstance = (HANDLE) hInst;
\r
6017 openFileName.lpstrFilter = nameFilt;
\r
6018 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6019 openFileName.nMaxCustFilter = 0L;
\r
6020 openFileName.nFilterIndex = 1L;
\r
6021 openFileName.lpstrFile = fileName;
\r
6022 openFileName.nMaxFile = MSG_SIZ;
\r
6023 openFileName.lpstrFileTitle = fileTitle;
\r
6024 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6025 openFileName.lpstrInitialDir = NULL;
\r
6026 openFileName.lpstrTitle = dlgTitle;
\r
6027 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6028 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6029 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6030 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6031 openFileName.nFileOffset = 0;
\r
6032 openFileName.nFileExtension = 0;
\r
6033 openFileName.lpstrDefExt = defExt;
\r
6034 openFileName.lCustData = (LONG) number;
\r
6035 openFileName.lpfnHook = oldDialog ?
\r
6036 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6037 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6039 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6040 GetOpenFileName(&openFileName)) {
\r
6041 /* open the file */
\r
6042 f = fopen(openFileName.lpstrFile, write);
\r
6044 MessageBox(hwnd, _("File open failed"), NULL,
\r
6045 MB_OK|MB_ICONEXCLAMATION);
\r
6049 int err = CommDlgExtendedError();
\r
6050 if (err != 0) DisplayError(_("Internal error in file dialog box"), err);
\r
6059 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6061 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6064 * Get the first pop-up menu in the menu template. This is the
\r
6065 * menu that TrackPopupMenu displays.
\r
6067 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6068 TranslateOneMenu(10, hmenuTrackPopup);
\r
6070 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6073 * TrackPopup uses screen coordinates, so convert the
\r
6074 * coordinates of the mouse click to screen coordinates.
\r
6076 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6078 /* Draw and track the floating pop-up menu. */
\r
6079 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6080 pt.x, pt.y, 0, hwnd, NULL);
\r
6082 /* Destroy the menu.*/
\r
6083 DestroyMenu(hmenu);
\r
6088 int sizeX, sizeY, newSizeX, newSizeY;
\r
6090 } ResizeEditPlusButtonsClosure;
\r
6093 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6095 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6099 if (hChild == cl->hText) return TRUE;
\r
6100 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6101 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6102 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6103 ScreenToClient(cl->hDlg, &pt);
\r
6104 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6105 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6109 /* Resize a dialog that has a (rich) edit field filling most of
\r
6110 the top, with a row of buttons below */
\r
6112 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6115 int newTextHeight, newTextWidth;
\r
6116 ResizeEditPlusButtonsClosure cl;
\r
6118 /*if (IsIconic(hDlg)) return;*/
\r
6119 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6121 cl.hdwp = BeginDeferWindowPos(8);
\r
6123 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6124 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6125 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6126 if (newTextHeight < 0) {
\r
6127 newSizeY += -newTextHeight;
\r
6128 newTextHeight = 0;
\r
6130 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6131 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6137 cl.newSizeX = newSizeX;
\r
6138 cl.newSizeY = newSizeY;
\r
6139 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6141 EndDeferWindowPos(cl.hdwp);
\r
6144 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6146 RECT rChild, rParent;
\r
6147 int wChild, hChild, wParent, hParent;
\r
6148 int wScreen, hScreen, xNew, yNew;
\r
6151 /* Get the Height and Width of the child window */
\r
6152 GetWindowRect (hwndChild, &rChild);
\r
6153 wChild = rChild.right - rChild.left;
\r
6154 hChild = rChild.bottom - rChild.top;
\r
6156 /* Get the Height and Width of the parent window */
\r
6157 GetWindowRect (hwndParent, &rParent);
\r
6158 wParent = rParent.right - rParent.left;
\r
6159 hParent = rParent.bottom - rParent.top;
\r
6161 /* Get the display limits */
\r
6162 hdc = GetDC (hwndChild);
\r
6163 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6164 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6165 ReleaseDC(hwndChild, hdc);
\r
6167 /* Calculate new X position, then adjust for screen */
\r
6168 xNew = rParent.left + ((wParent - wChild) /2);
\r
6171 } else if ((xNew+wChild) > wScreen) {
\r
6172 xNew = wScreen - wChild;
\r
6175 /* Calculate new Y position, then adjust for screen */
\r
6177 yNew = rParent.top + ((hParent - hChild) /2);
\r
6180 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6185 } else if ((yNew+hChild) > hScreen) {
\r
6186 yNew = hScreen - hChild;
\r
6189 /* Set it, and return */
\r
6190 return SetWindowPos (hwndChild, NULL,
\r
6191 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6194 /* Center one window over another */
\r
6195 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6197 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6200 /*---------------------------------------------------------------------------*\
\r
6202 * Startup Dialog functions
\r
6204 \*---------------------------------------------------------------------------*/
\r
6206 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6208 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6210 while (*cd != NULL) {
\r
6211 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) T_(*cd));
\r
6217 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6219 char buf1[MAX_ARG_LEN];
\r
6222 if (str[0] == '@') {
\r
6223 FILE* f = fopen(str + 1, "r");
\r
6225 DisplayFatalError(str + 1, errno, 2);
\r
6228 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6230 buf1[len] = NULLCHAR;
\r
6234 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6237 char buf[MSG_SIZ];
\r
6238 char *end = strchr(str, '\n');
\r
6239 if (end == NULL) return;
\r
6240 memcpy(buf, str, end - str);
\r
6241 buf[end - str] = NULLCHAR;
\r
6242 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6248 SetStartupDialogEnables(HWND hDlg)
\r
6250 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6251 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6252 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6253 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6254 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6255 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6256 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6257 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6258 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6259 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6260 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6261 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6262 IsDlgButtonChecked(hDlg, OPT_View));
\r
6266 QuoteForFilename(char *filename)
\r
6268 int dquote, space;
\r
6269 dquote = strchr(filename, '"') != NULL;
\r
6270 space = strchr(filename, ' ') != NULL;
\r
6271 if (dquote || space) {
\r
6283 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6285 char buf[MSG_SIZ];
\r
6288 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6289 q = QuoteForFilename(nthcp);
\r
6290 snprintf(buf, MSG_SIZ, "%s%s%s", q, nthcp, q);
\r
6291 if (*nthdir != NULLCHAR) {
\r
6292 q = QuoteForFilename(nthdir);
\r
6293 snprintf(buf + strlen(buf), MSG_SIZ, " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6295 if (*nthcp == NULLCHAR) {
\r
6296 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6297 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6298 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6299 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6304 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6306 char buf[MSG_SIZ];
\r
6310 switch (message) {
\r
6311 case WM_INITDIALOG:
\r
6312 /* Center the dialog */
\r
6313 CenterWindow (hDlg, GetDesktopWindow());
\r
6314 Translate(hDlg, DLG_Startup);
\r
6315 /* Initialize the dialog items */
\r
6316 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6317 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6318 firstChessProgramNames);
\r
6319 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6320 appData.secondChessProgram, singleList ? "fd" : "sd", appData.secondDirectory,
\r
6321 singleList ? firstChessProgramNames : secondChessProgramNames); //[HGM] single: use first list in second combo
\r
6322 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6323 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6324 snprintf(buf, MSG_SIZ, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6325 if (*appData.icsHelper != NULLCHAR) {
\r
6326 char *q = QuoteForFilename(appData.icsHelper);
\r
6327 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6329 if (*appData.icsHost == NULLCHAR) {
\r
6330 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6331 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6332 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6333 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6334 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6337 if (appData.icsActive) {
\r
6338 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6340 else if (appData.noChessProgram) {
\r
6341 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6344 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6347 SetStartupDialogEnables(hDlg);
\r
6351 switch (LOWORD(wParam)) {
\r
6353 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6354 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6355 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6357 comboLine = strdup(p+5); // [HGM] recent: remember complete line of first combobox
\r
6358 ParseArgs(StringGet, &p);
\r
6359 safeStrCpy(buf, singleList ? "/fcp=" : "/scp=", sizeof(buf)/sizeof(buf[0]) );
\r
6360 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6362 SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...
\r
6363 ParseArgs(StringGet, &p);
\r
6364 SwapEngines(singleList); // ... and then make it 'second'
\r
6366 appData.noChessProgram = FALSE;
\r
6367 appData.icsActive = FALSE;
\r
6368 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6369 safeStrCpy(buf, "/ics /icshost=", sizeof(buf)/sizeof(buf[0]) );
\r
6370 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6372 ParseArgs(StringGet, &p);
\r
6373 if (appData.zippyPlay) {
\r
6374 safeStrCpy(buf, "/fcp=", sizeof(buf)/sizeof(buf[0]) );
\r
6375 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6377 ParseArgs(StringGet, &p);
\r
6379 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6380 appData.noChessProgram = TRUE;
\r
6381 appData.icsActive = FALSE;
\r
6383 MessageBox(hDlg, _("Choose an option, or cancel to exit"),
\r
6384 _("Option Error"), MB_OK|MB_ICONEXCLAMATION);
\r
6387 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6388 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6390 ParseArgs(StringGet, &p);
\r
6392 EndDialog(hDlg, TRUE);
\r
6399 case IDM_HELPCONTENTS:
\r
6400 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6401 MessageBox (GetFocus(),
\r
6402 _("Unable to activate help"),
\r
6403 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6408 SetStartupDialogEnables(hDlg);
\r
6416 /*---------------------------------------------------------------------------*\
\r
6418 * About box dialog functions
\r
6420 \*---------------------------------------------------------------------------*/
\r
6422 /* Process messages for "About" dialog box */
\r
6424 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6426 switch (message) {
\r
6427 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6428 /* Center the dialog over the application window */
\r
6429 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6430 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6431 Translate(hDlg, ABOUTBOX);
\r
6435 case WM_COMMAND: /* message: received a command */
\r
6436 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6437 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6438 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6446 /*---------------------------------------------------------------------------*\
\r
6448 * Comment Dialog functions
\r
6450 \*---------------------------------------------------------------------------*/
\r
6453 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6455 static HANDLE hwndText = NULL;
\r
6456 int len, newSizeX, newSizeY;
\r
6457 static int sizeX, sizeY;
\r
6462 switch (message) {
\r
6463 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6464 /* Initialize the dialog items */
\r
6465 Translate(hDlg, DLG_EditComment);
\r
6466 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6467 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6468 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6469 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6470 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6471 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6472 SetWindowText(hDlg, commentTitle);
\r
6473 if (editComment) {
\r
6474 SetFocus(hwndText);
\r
6476 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6478 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6479 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6480 MAKELPARAM(FALSE, 0));
\r
6481 /* Size and position the dialog */
\r
6482 if (!commentDialog) {
\r
6483 commentDialog = hDlg;
\r
6484 GetClientRect(hDlg, &rect);
\r
6485 sizeX = rect.right;
\r
6486 sizeY = rect.bottom;
\r
6487 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6488 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6489 WINDOWPLACEMENT wp;
\r
6490 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6491 wp.length = sizeof(WINDOWPLACEMENT);
\r
6493 wp.showCmd = SW_SHOW;
\r
6494 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6495 wp.rcNormalPosition.left = wpComment.x;
\r
6496 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6497 wp.rcNormalPosition.top = wpComment.y;
\r
6498 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6499 SetWindowPlacement(hDlg, &wp);
\r
6501 GetClientRect(hDlg, &rect);
\r
6502 newSizeX = rect.right;
\r
6503 newSizeY = rect.bottom;
\r
6504 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6505 newSizeX, newSizeY);
\r
6510 SendDlgItemMessage( hDlg, OPT_CommentText, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS );
\r
6513 case WM_COMMAND: /* message: received a command */
\r
6514 switch (LOWORD(wParam)) {
\r
6516 if (editComment) {
\r
6518 /* Read changed options from the dialog box */
\r
6519 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6520 len = GetWindowTextLength(hwndText);
\r
6521 str = (char *) malloc(len + 1);
\r
6522 GetWindowText(hwndText, str, len + 1);
\r
6531 ReplaceComment(commentIndex, str);
\r
6538 case OPT_CancelComment:
\r
6542 case OPT_ClearComment:
\r
6543 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6546 case OPT_EditComment:
\r
6547 EditCommentEvent();
\r
6555 case WM_NOTIFY: // [HGM] vari: cloned from whistory.c
\r
6556 if( wParam == OPT_CommentText ) {
\r
6557 MSGFILTER * lpMF = (MSGFILTER *) lParam;
\r
6559 if( lpMF->msg == WM_RBUTTONDOWN && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ||
\r
6560 lpMF->msg == WM_CHAR && lpMF->wParam == '\022' ) {
\r
6564 pt.x = LOWORD( lpMF->lParam );
\r
6565 pt.y = HIWORD( lpMF->lParam );
\r
6567 if(lpMF->msg == WM_CHAR) {
\r
6569 SendDlgItemMessage( hDlg, OPT_CommentText, EM_EXGETSEL, 0, (LPARAM) &sel );
\r
6570 index = sel.cpMin;
\r
6572 index = SendDlgItemMessage( hDlg, OPT_CommentText, EM_CHARFROMPOS, 0, (LPARAM) &pt );
\r
6574 hwndText = GetDlgItem(hDlg, OPT_CommentText); // cloned from above
\r
6575 len = GetWindowTextLength(hwndText);
\r
6576 str = (char *) malloc(len + 1);
\r
6577 GetWindowText(hwndText, str, len + 1);
\r
6578 ReplaceComment(commentIndex, str);
\r
6579 if(commentIndex != currentMove) ToNrEvent(commentIndex);
\r
6580 LoadVariation( index, str ); // [HGM] also does the actual moving to it, now
\r
6583 /* Zap the message for good: apparently, returning non-zero is not enough */
\r
6584 lpMF->msg = WM_USER;
\r
6592 newSizeX = LOWORD(lParam);
\r
6593 newSizeY = HIWORD(lParam);
\r
6594 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6599 case WM_GETMINMAXINFO:
\r
6600 /* Prevent resizing window too small */
\r
6601 mmi = (MINMAXINFO *) lParam;
\r
6602 mmi->ptMinTrackSize.x = 100;
\r
6603 mmi->ptMinTrackSize.y = 100;
\r
6610 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6615 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6617 if (str == NULL) str = "";
\r
6618 p = (char *) malloc(2 * strlen(str) + 2);
\r
6621 if (*str == '\n') *q++ = '\r';
\r
6625 if (commentText != NULL) free(commentText);
\r
6627 commentIndex = index;
\r
6628 commentTitle = title;
\r
6630 editComment = edit;
\r
6632 if (commentDialog) {
\r
6633 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6634 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6636 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6637 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6638 hwndMain, (DLGPROC)lpProc);
\r
6639 FreeProcInstance(lpProc);
\r
6645 /*---------------------------------------------------------------------------*\
\r
6647 * Type-in move dialog functions
\r
6649 \*---------------------------------------------------------------------------*/
\r
6652 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6654 char move[MSG_SIZ];
\r
6657 switch (message) {
\r
6658 case WM_INITDIALOG:
\r
6659 move[0] = (char) lParam;
\r
6660 move[1] = NULLCHAR;
\r
6661 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6662 Translate(hDlg, DLG_TypeInMove);
\r
6663 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6664 SetWindowText(hInput, move);
\r
6666 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6670 switch (LOWORD(wParam)) {
\r
6673 shiftKey = GetKeyState(VK_SHIFT) < 0; // [HGM] remember last shift status
\r
6674 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6675 TypeInDoneEvent(move);
\r
6676 EndDialog(hDlg, TRUE);
\r
6679 EndDialog(hDlg, FALSE);
\r
6690 PopUpMoveDialog(char firstchar)
\r
6694 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6695 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6696 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6697 FreeProcInstance(lpProc);
\r
6700 /*---------------------------------------------------------------------------*\
\r
6702 * Type-in name dialog functions
\r
6704 \*---------------------------------------------------------------------------*/
\r
6707 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6709 char move[MSG_SIZ];
\r
6712 switch (message) {
\r
6713 case WM_INITDIALOG:
\r
6714 move[0] = (char) lParam;
\r
6715 move[1] = NULLCHAR;
\r
6716 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6717 Translate(hDlg, DLG_TypeInName);
\r
6718 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6719 SetWindowText(hInput, move);
\r
6721 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6725 switch (LOWORD(wParam)) {
\r
6727 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6728 appData.userName = strdup(move);
\r
6731 if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) {
\r
6732 snprintf(move, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
\r
6733 DisplayTitle(move);
\r
6737 EndDialog(hDlg, TRUE);
\r
6740 EndDialog(hDlg, FALSE);
\r
6751 PopUpNameDialog(char firstchar)
\r
6755 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6756 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6757 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6758 FreeProcInstance(lpProc);
\r
6761 /*---------------------------------------------------------------------------*\
\r
6765 \*---------------------------------------------------------------------------*/
\r
6767 /* Nonmodal error box */
\r
6768 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6769 WPARAM wParam, LPARAM lParam);
\r
6772 ErrorPopUp(char *title, char *content)
\r
6776 BOOLEAN modal = hwndMain == NULL;
\r
6794 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6795 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6798 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6800 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6801 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6802 hwndMain, (DLGPROC)lpProc);
\r
6803 FreeProcInstance(lpProc);
\r
6810 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6811 if (errorDialog == NULL) return;
\r
6812 DestroyWindow(errorDialog);
\r
6813 errorDialog = NULL;
\r
6814 if(errorExitStatus) ExitEvent(errorExitStatus);
\r
6818 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6822 switch (message) {
\r
6823 case WM_INITDIALOG:
\r
6824 GetWindowRect(hDlg, &rChild);
\r
6827 SetWindowPos(hDlg, NULL, rChild.left,
\r
6828 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6829 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6833 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6834 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6835 and it doesn't work when you resize the dialog.
\r
6836 For now, just give it a default position.
\r
6838 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6839 Translate(hDlg, DLG_Error);
\r
6841 errorDialog = hDlg;
\r
6842 SetWindowText(hDlg, errorTitle);
\r
6843 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6847 switch (LOWORD(wParam)) {
\r
6850 if (errorDialog == hDlg) errorDialog = NULL;
\r
6851 DestroyWindow(hDlg);
\r
6863 HWND gothicDialog = NULL;
\r
6866 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6869 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6871 switch (message) {
\r
6872 case WM_INITDIALOG:
\r
6873 GetWindowRect(hDlg, &rChild);
\r
6875 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
6879 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6880 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6881 and it doesn't work when you resize the dialog.
\r
6882 For now, just give it a default position.
\r
6884 gothicDialog = hDlg;
\r
6885 SetWindowText(hDlg, errorTitle);
\r
6886 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6890 switch (LOWORD(wParam)) {
\r
6893 if (errorDialog == hDlg) errorDialog = NULL;
\r
6894 DestroyWindow(hDlg);
\r
6906 GothicPopUp(char *title, VariantClass variant)
\r
6909 static char *lastTitle;
\r
6911 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6912 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6914 if(lastTitle != title && gothicDialog != NULL) {
\r
6915 DestroyWindow(gothicDialog);
\r
6916 gothicDialog = NULL;
\r
6918 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6919 title = lastTitle;
\r
6920 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6921 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6922 hwndMain, (DLGPROC)lpProc);
\r
6923 FreeProcInstance(lpProc);
\r
6928 /*---------------------------------------------------------------------------*\
\r
6930 * Ics Interaction console functions
\r
6932 \*---------------------------------------------------------------------------*/
\r
6934 #define HISTORY_SIZE 64
\r
6935 static char *history[HISTORY_SIZE];
\r
6936 int histIn = 0, histP = 0;
\r
6940 SaveInHistory(char *cmd)
\r
6942 if (history[histIn] != NULL) {
\r
6943 free(history[histIn]);
\r
6944 history[histIn] = NULL;
\r
6946 if (*cmd == NULLCHAR) return;
\r
6947 history[histIn] = StrSave(cmd);
\r
6948 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6949 if (history[histIn] != NULL) {
\r
6950 free(history[histIn]);
\r
6952 history[histIn] = NULL;
\r
6958 PrevInHistory(char *cmd)
\r
6961 if (histP == histIn) {
\r
6962 if (history[histIn] != NULL) free(history[histIn]);
\r
6963 history[histIn] = StrSave(cmd);
\r
6965 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6966 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6968 return history[histP];
\r
6974 if (histP == histIn) return NULL;
\r
6975 histP = (histP + 1) % HISTORY_SIZE;
\r
6976 return history[histP];
\r
6980 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6984 hmenu = LoadMenu(hInst, "TextMenu");
\r
6985 h = GetSubMenu(hmenu, 0);
\r
6987 if (strcmp(e->item, "-") == 0) {
\r
6988 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6989 } else { // [HGM] re-written a bit to use only one AppendMenu call for both cases (| or no |)
\r
6990 int flags = MF_STRING, j = 0;
\r
6991 if (e->item[0] == '|') {
\r
6992 flags |= MF_MENUBARBREAK;
\r
6995 if(!strcmp(e->command, "none")) flags |= MF_GRAYED; // [HGM] chatclick: provide inactive dummy
\r
6996 AppendMenu(h, flags, IDM_CommandX + i, e->item + j);
\r
7004 WNDPROC consoleTextWindowProc;
\r
7007 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7009 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7010 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7014 SetWindowText(hInput, command);
\r
7016 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7018 sel.cpMin = 999999;
\r
7019 sel.cpMax = 999999;
\r
7020 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7025 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7026 if (sel.cpMin == sel.cpMax) {
\r
7027 /* Expand to surrounding word */
\r
7030 tr.chrg.cpMax = sel.cpMin;
\r
7031 tr.chrg.cpMin = --sel.cpMin;
\r
7032 if (sel.cpMin < 0) break;
\r
7033 tr.lpstrText = name;
\r
7034 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7035 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7039 tr.chrg.cpMin = sel.cpMax;
\r
7040 tr.chrg.cpMax = ++sel.cpMax;
\r
7041 tr.lpstrText = name;
\r
7042 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7043 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7046 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7047 MessageBeep(MB_ICONEXCLAMATION);
\r
7051 tr.lpstrText = name;
\r
7052 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7054 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7055 MessageBeep(MB_ICONEXCLAMATION);
\r
7058 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7061 if(strstr(command, "%s")) snprintf(buf, MSG_SIZ, command, name); else
\r
7062 snprintf(buf, MSG_SIZ, "%s %s", command, name);
\r
7063 SetWindowText(hInput, buf);
\r
7064 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7066 if(!strcmp(command, "chat")) { ChatPopUp(name); return; }
\r
7067 snprintf(buf, MSG_SIZ, "%s %s ", command, name); /* trailing space */
\r
7068 SetWindowText(hInput, buf);
\r
7069 sel.cpMin = 999999;
\r
7070 sel.cpMax = 999999;
\r
7071 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7077 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7082 switch (message) {
\r
7084 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7085 if(wParam=='R') return 0;
\r
7088 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7091 sel.cpMin = 999999;
\r
7092 sel.cpMax = 999999;
\r
7093 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7094 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7099 if(wParam != '\022') {
\r
7100 if (wParam == '\t') {
\r
7101 if (GetKeyState(VK_SHIFT) < 0) {
\r
7103 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7104 if (buttonDesc[0].hwnd) {
\r
7105 SetFocus(buttonDesc[0].hwnd);
\r
7107 SetFocus(hwndMain);
\r
7111 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7114 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7115 JAWS_DELETE( SetFocus(hInput); )
\r
7116 SendMessage(hInput, message, wParam, lParam);
\r
7119 } // [HGM] navigate: for Ctrl+R, flow into next case (moved up here) to summon up menu
\r
7121 case WM_RBUTTONDOWN:
\r
7122 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7123 /* Move selection here if it was empty */
\r
7125 pt.x = LOWORD(lParam);
\r
7126 pt.y = HIWORD(lParam);
\r
7127 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7128 if (sel.cpMin == sel.cpMax) {
\r
7129 if(lParam != -1) sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7130 sel.cpMax = sel.cpMin;
\r
7131 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7133 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7134 { // [HGM] chatclick: code moved here from WM_RBUTTONUP case, to have menu appear on down-click
\r
7136 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7137 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7138 if (sel.cpMin == sel.cpMax) {
\r
7139 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7140 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7142 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7143 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7145 pt.x = LOWORD(lParam)-30; // [HGM] chatclick: make menu pop up with pointer above upper-right item
\r
7146 pt.y = HIWORD(lParam)-10; // make it appear as if mouse moved there, so it will be selected on up-click
\r
7147 PostMessage(hwnd, WM_MOUSEMOVE, wParam, lParam+5);
\r
7148 MenuPopup(hwnd, pt, hmenu, -1);
\r
7152 case WM_RBUTTONUP:
\r
7153 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7154 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7155 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7159 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7161 return SendMessage(hInput, message, wParam, lParam);
\r
7162 case WM_MBUTTONDOWN:
\r
7163 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7165 switch (LOWORD(wParam)) {
\r
7166 case IDM_QuickPaste:
\r
7168 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7169 if (sel.cpMin == sel.cpMax) {
\r
7170 MessageBeep(MB_ICONEXCLAMATION);
\r
7173 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7174 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7175 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7180 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7183 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7186 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7190 int i = LOWORD(wParam) - IDM_CommandX;
\r
7191 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7192 icsTextMenuEntry[i].command != NULL) {
\r
7193 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7194 icsTextMenuEntry[i].getname,
\r
7195 icsTextMenuEntry[i].immediate);
\r
7203 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7206 WNDPROC consoleInputWindowProc;
\r
7209 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7211 char buf[MSG_SIZ];
\r
7213 static BOOL sendNextChar = FALSE;
\r
7214 static BOOL quoteNextChar = FALSE;
\r
7215 InputSource *is = consoleInputSource;
\r
7219 switch (message) {
\r
7221 if (!appData.localLineEditing || sendNextChar) {
\r
7222 is->buf[0] = (CHAR) wParam;
\r
7224 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7225 sendNextChar = FALSE;
\r
7228 if (quoteNextChar) {
\r
7229 buf[0] = (char) wParam;
\r
7230 buf[1] = NULLCHAR;
\r
7231 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7232 quoteNextChar = FALSE;
\r
7236 case '\r': /* Enter key */
\r
7237 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7238 if (consoleEcho) SaveInHistory(is->buf);
\r
7239 is->buf[is->count++] = '\n';
\r
7240 is->buf[is->count] = NULLCHAR;
\r
7241 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7242 if (consoleEcho) {
\r
7243 ConsoleOutput(is->buf, is->count, TRUE);
\r
7244 } else if (appData.localLineEditing) {
\r
7245 ConsoleOutput("\n", 1, TRUE);
\r
7248 case '\033': /* Escape key */
\r
7249 SetWindowText(hwnd, "");
\r
7250 cf.cbSize = sizeof(CHARFORMAT);
\r
7251 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7252 if (consoleEcho) {
\r
7253 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7255 cf.crTextColor = COLOR_ECHOOFF;
\r
7257 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7258 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7260 case '\t': /* Tab key */
\r
7261 if (GetKeyState(VK_SHIFT) < 0) {
\r
7263 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7266 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7267 if (buttonDesc[0].hwnd) {
\r
7268 SetFocus(buttonDesc[0].hwnd);
\r
7270 SetFocus(hwndMain);
\r
7274 case '\023': /* Ctrl+S */
\r
7275 sendNextChar = TRUE;
\r
7277 case '\021': /* Ctrl+Q */
\r
7278 quoteNextChar = TRUE;
\r
7288 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7289 p = PrevInHistory(buf);
\r
7291 SetWindowText(hwnd, p);
\r
7292 sel.cpMin = 999999;
\r
7293 sel.cpMax = 999999;
\r
7294 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7299 p = NextInHistory();
\r
7301 SetWindowText(hwnd, p);
\r
7302 sel.cpMin = 999999;
\r
7303 sel.cpMax = 999999;
\r
7304 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7310 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7314 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7318 case WM_MBUTTONDOWN:
\r
7319 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7320 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7322 case WM_RBUTTONUP:
\r
7323 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7324 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7325 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7329 hmenu = LoadMenu(hInst, "InputMenu");
\r
7330 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7331 if (sel.cpMin == sel.cpMax) {
\r
7332 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7333 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7335 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7336 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7338 pt.x = LOWORD(lParam);
\r
7339 pt.y = HIWORD(lParam);
\r
7340 MenuPopup(hwnd, pt, hmenu, -1);
\r
7344 switch (LOWORD(wParam)) {
\r
7346 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7348 case IDM_SelectAll:
\r
7350 sel.cpMax = -1; /*999999?*/
\r
7351 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7354 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7357 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7360 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7365 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7368 #define CO_MAX 100000
\r
7369 #define CO_TRIM 1000
\r
7372 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7374 static SnapData sd;
\r
7375 HWND hText, hInput;
\r
7377 static int sizeX, sizeY;
\r
7378 int newSizeX, newSizeY;
\r
7382 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7383 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7385 switch (message) {
\r
7387 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7389 ENLINK *pLink = (ENLINK*)lParam;
\r
7390 if (pLink->msg == WM_LBUTTONUP)
\r
7394 tr.chrg = pLink->chrg;
\r
7395 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7396 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7397 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7398 free(tr.lpstrText);
\r
7402 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7403 hwndConsole = hDlg;
\r
7405 consoleTextWindowProc = (WNDPROC)
\r
7406 SetWindowLongPtr(hText, GWLP_WNDPROC, (LONG_PTR) ConsoleTextSubclass);
\r
7407 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7408 consoleInputWindowProc = (WNDPROC)
\r
7409 SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR) ConsoleInputSubclass);
\r
7410 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7411 Colorize(ColorNormal, TRUE);
\r
7412 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7413 ChangedConsoleFont();
\r
7414 GetClientRect(hDlg, &rect);
\r
7415 sizeX = rect.right;
\r
7416 sizeY = rect.bottom;
\r
7417 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7418 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7419 WINDOWPLACEMENT wp;
\r
7420 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7421 wp.length = sizeof(WINDOWPLACEMENT);
\r
7423 wp.showCmd = SW_SHOW;
\r
7424 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7425 wp.rcNormalPosition.left = wpConsole.x;
\r
7426 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7427 wp.rcNormalPosition.top = wpConsole.y;
\r
7428 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7429 SetWindowPlacement(hDlg, &wp);
\r
7432 // [HGM] Chessknight's change 2004-07-13
\r
7433 else { /* Determine Defaults */
\r
7434 WINDOWPLACEMENT wp;
\r
7435 wpConsole.x = wpMain.width + 1;
\r
7436 wpConsole.y = wpMain.y;
\r
7437 wpConsole.width = screenWidth - wpMain.width;
\r
7438 wpConsole.height = wpMain.height;
\r
7439 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7440 wp.length = sizeof(WINDOWPLACEMENT);
\r
7442 wp.showCmd = SW_SHOW;
\r
7443 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7444 wp.rcNormalPosition.left = wpConsole.x;
\r
7445 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7446 wp.rcNormalPosition.top = wpConsole.y;
\r
7447 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7448 SetWindowPlacement(hDlg, &wp);
\r
7451 // Allow hText to highlight URLs and send notifications on them
\r
7452 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7453 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7454 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7455 SetWindowLongPtr(hText, GWLP_USERDATA, 79); // initialize the text window's width
\r
7469 if (IsIconic(hDlg)) break;
\r
7470 newSizeX = LOWORD(lParam);
\r
7471 newSizeY = HIWORD(lParam);
\r
7472 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7473 RECT rectText, rectInput;
\r
7475 int newTextHeight, newTextWidth;
\r
7476 GetWindowRect(hText, &rectText);
\r
7477 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7478 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7479 if (newTextHeight < 0) {
\r
7480 newSizeY += -newTextHeight;
\r
7481 newTextHeight = 0;
\r
7483 SetWindowPos(hText, NULL, 0, 0,
\r
7484 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7485 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7486 pt.x = rectInput.left;
\r
7487 pt.y = rectInput.top + newSizeY - sizeY;
\r
7488 ScreenToClient(hDlg, &pt);
\r
7489 SetWindowPos(hInput, NULL,
\r
7490 pt.x, pt.y, /* needs client coords */
\r
7491 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7492 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7498 case WM_GETMINMAXINFO:
\r
7499 /* Prevent resizing window too small */
\r
7500 mmi = (MINMAXINFO *) lParam;
\r
7501 mmi->ptMinTrackSize.x = 100;
\r
7502 mmi->ptMinTrackSize.y = 100;
\r
7505 /* [AS] Snapping */
\r
7506 case WM_ENTERSIZEMOVE:
\r
7507 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7510 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7513 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7515 case WM_EXITSIZEMOVE:
\r
7516 UpdateICSWidth(hText);
\r
7517 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7520 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7528 if (hwndConsole) return;
\r
7529 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7530 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7535 ConsoleOutput(char* data, int length, int forceVisible)
\r
7540 char buf[CO_MAX+1];
\r
7543 static int delayLF = 0;
\r
7544 CHARRANGE savesel, sel;
\r
7546 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7554 while (length--) {
\r
7562 } else if (*p == '\007') {
\r
7563 MyPlaySound(&sounds[(int)SoundBell]);
\r
7570 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7571 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7572 /* Save current selection */
\r
7573 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7574 exlen = GetWindowTextLength(hText);
\r
7575 /* Find out whether current end of text is visible */
\r
7576 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7577 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7578 /* Trim existing text if it's too long */
\r
7579 if (exlen + (q - buf) > CO_MAX) {
\r
7580 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7583 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7584 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7586 savesel.cpMin -= trim;
\r
7587 savesel.cpMax -= trim;
\r
7588 if (exlen < 0) exlen = 0;
\r
7589 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7590 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7592 /* Append the new text */
\r
7593 sel.cpMin = exlen;
\r
7594 sel.cpMax = exlen;
\r
7595 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7596 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7597 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7598 if (forceVisible || exlen == 0 ||
\r
7599 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7600 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7601 /* Scroll to make new end of text visible if old end of text
\r
7602 was visible or new text is an echo of user typein */
\r
7603 sel.cpMin = 9999999;
\r
7604 sel.cpMax = 9999999;
\r
7605 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7606 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7607 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7608 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7610 if (savesel.cpMax == exlen || forceVisible) {
\r
7611 /* Move insert point to new end of text if it was at the old
\r
7612 end of text or if the new text is an echo of user typein */
\r
7613 sel.cpMin = 9999999;
\r
7614 sel.cpMax = 9999999;
\r
7615 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7617 /* Restore previous selection */
\r
7618 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7620 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7627 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7631 COLORREF oldFg, oldBg;
\r
7635 if(copyNumber > 1)
\r
7636 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", copyNumber); else buf[0] = 0;
\r
7638 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7639 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7640 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7643 rect.right = x + squareSize;
\r
7645 rect.bottom = y + squareSize;
\r
7648 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7649 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7650 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7651 &rect, str, strlen(str), NULL);
\r
7653 (void) SetTextColor(hdc, oldFg);
\r
7654 (void) SetBkColor(hdc, oldBg);
\r
7655 (void) SelectObject(hdc, oldFont);
\r
7659 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7660 RECT *rect, char *color, char *flagFell)
\r
7664 COLORREF oldFg, oldBg;
\r
7667 if (twoBoards && partnerUp) return;
\r
7668 if (appData.clockMode) {
\r
7669 if (tinyLayout == 2)
\r
7670 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7672 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
7679 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7680 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7682 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7683 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7686 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7690 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7691 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7692 rect, str, strlen(str), NULL);
\r
7693 if(logoHeight > 0 && appData.clockMode) {
\r
7695 str += strlen(color)+2;
\r
7696 r.top = rect->top + logoHeight/2;
\r
7697 r.left = rect->left;
\r
7698 r.right = rect->right;
\r
7699 r.bottom = rect->bottom;
\r
7700 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7701 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
7702 &r, str, strlen(str), NULL);
\r
7704 (void) SetTextColor(hdc, oldFg);
\r
7705 (void) SetBkColor(hdc, oldBg);
\r
7706 (void) SelectObject(hdc, oldFont);
\r
7711 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7717 if( count <= 0 ) {
\r
7718 if (appData.debugMode) {
\r
7719 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7722 return ERROR_INVALID_USER_BUFFER;
\r
7725 ResetEvent(ovl->hEvent);
\r
7726 ovl->Offset = ovl->OffsetHigh = 0;
\r
7727 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7731 err = GetLastError();
\r
7732 if (err == ERROR_IO_PENDING) {
\r
7733 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7737 err = GetLastError();
\r
7744 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7749 ResetEvent(ovl->hEvent);
\r
7750 ovl->Offset = ovl->OffsetHigh = 0;
\r
7751 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7755 err = GetLastError();
\r
7756 if (err == ERROR_IO_PENDING) {
\r
7757 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7761 err = GetLastError();
\r
7768 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7769 void CheckForInputBufferFull( InputSource * is )
\r
7771 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7772 /* Look for end of line */
\r
7773 char * p = is->buf;
\r
7775 while( p < is->next && *p != '\n' ) {
\r
7779 if( p >= is->next ) {
\r
7780 if (appData.debugMode) {
\r
7781 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
7784 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7785 is->count = (DWORD) -1;
\r
7786 is->next = is->buf;
\r
7792 InputThread(LPVOID arg)
\r
7797 is = (InputSource *) arg;
\r
7798 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7799 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7800 while (is->hThread != NULL) {
\r
7801 is->error = DoReadFile(is->hFile, is->next,
\r
7802 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7803 &is->count, &ovl);
\r
7804 if (is->error == NO_ERROR) {
\r
7805 is->next += is->count;
\r
7807 if (is->error == ERROR_BROKEN_PIPE) {
\r
7808 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7811 is->count = (DWORD) -1;
\r
7812 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7817 CheckForInputBufferFull( is );
\r
7819 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7821 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7823 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7826 CloseHandle(ovl.hEvent);
\r
7827 CloseHandle(is->hFile);
\r
7829 if (appData.debugMode) {
\r
7830 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
7837 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7839 NonOvlInputThread(LPVOID arg)
\r
7846 is = (InputSource *) arg;
\r
7847 while (is->hThread != NULL) {
\r
7848 is->error = ReadFile(is->hFile, is->next,
\r
7849 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7850 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7851 if (is->error == NO_ERROR) {
\r
7852 /* Change CRLF to LF */
\r
7853 if (is->next > is->buf) {
\r
7855 i = is->count + 1;
\r
7863 if (prev == '\r' && *p == '\n') {
\r
7875 if (is->error == ERROR_BROKEN_PIPE) {
\r
7876 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7879 is->count = (DWORD) -1;
\r
7883 CheckForInputBufferFull( is );
\r
7885 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7887 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7889 if (is->count < 0) break; /* Quit on error */
\r
7891 CloseHandle(is->hFile);
\r
7896 SocketInputThread(LPVOID arg)
\r
7900 is = (InputSource *) arg;
\r
7901 while (is->hThread != NULL) {
\r
7902 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7903 if ((int)is->count == SOCKET_ERROR) {
\r
7904 is->count = (DWORD) -1;
\r
7905 is->error = WSAGetLastError();
\r
7907 is->error = NO_ERROR;
\r
7908 is->next += is->count;
\r
7909 if (is->count == 0 && is->second == is) {
\r
7910 /* End of file on stderr; quit with no message */
\r
7914 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7916 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7918 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7924 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7928 is = (InputSource *) lParam;
\r
7929 if (is->lineByLine) {
\r
7930 /* Feed in lines one by one */
\r
7931 char *p = is->buf;
\r
7933 while (q < is->next) {
\r
7934 if (*q++ == '\n') {
\r
7935 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7940 /* Move any partial line to the start of the buffer */
\r
7942 while (p < is->next) {
\r
7947 if (is->error != NO_ERROR || is->count == 0) {
\r
7948 /* Notify backend of the error. Note: If there was a partial
\r
7949 line at the end, it is not flushed through. */
\r
7950 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7953 /* Feed in the whole chunk of input at once */
\r
7954 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7955 is->next = is->buf;
\r
7959 /*---------------------------------------------------------------------------*\
\r
7961 * Menu enables. Used when setting various modes.
\r
7963 \*---------------------------------------------------------------------------*/
\r
7971 GreyRevert(Boolean grey)
\r
7972 { // [HGM] vari: for retracting variations in local mode
\r
7973 HMENU hmenu = GetMenu(hwndMain);
\r
7974 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7975 EnableMenuItem(hmenu, IDM_Annotate, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
7979 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7981 while (enab->item > 0) {
\r
7982 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7987 Enables gnuEnables[] = {
\r
7988 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7989 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7990 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7991 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7992 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7993 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7994 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7995 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7996 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7997 { IDM_Upload, MF_BYCOMMAND|MF_GRAYED },
\r
7998 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7999 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8000 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8003 // Needed to switch from ncp to GNU mode on Engine Load
\r
8004 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8005 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8006 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8007 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8008 { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8009 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8010 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_ENABLED },
\r
8011 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8012 { IDM_Engine2Options, MF_BYCOMMAND|MF_ENABLED },
\r
8013 { IDM_TimeControl, MF_BYCOMMAND|MF_ENABLED },
\r
8014 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8015 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8016 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8017 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8021 Enables icsEnables[] = {
\r
8022 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8024 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8025 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8026 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8027 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8028 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8029 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8031 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8032 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8033 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8034 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8035 { IDM_LoadProg1, MF_BYCOMMAND|MF_GRAYED },
\r
8036 { IDM_LoadProg2, MF_BYCOMMAND|MF_GRAYED },
\r
8037 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8038 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8039 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8040 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8041 { IDM_Tourney, MF_BYCOMMAND|MF_GRAYED },
\r
8046 Enables zippyEnables[] = {
\r
8047 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8048 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8049 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8050 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8055 Enables ncpEnables[] = {
\r
8056 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8062 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8063 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8064 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8065 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8066 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_Annotate, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8074 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8075 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8076 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8077 { IDM_Sounds, MF_BYCOMMAND|MF_GRAYED },
\r
8081 Enables trainingOnEnables[] = {
\r
8082 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8083 { IDM_Comment, MF_BYCOMMAND|MF_GRAYED },
\r
8084 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8085 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8086 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8087 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8088 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8089 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8090 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8094 Enables trainingOffEnables[] = {
\r
8095 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8096 { IDM_Comment, MF_BYCOMMAND|MF_ENABLED },
\r
8097 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8098 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8099 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8100 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8101 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8102 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8103 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8107 /* These modify either ncpEnables or gnuEnables */
\r
8108 Enables cmailEnables[] = {
\r
8109 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8110 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8111 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8112 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8114 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8115 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8119 Enables machineThinkingEnables[] = {
\r
8120 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8121 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8122 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8123 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8124 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8125 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8126 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8127 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8128 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8129 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8130 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8131 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8132 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8133 // { IDM_Match, MF_BYCOMMAND|MF_GRAYED },
\r
8134 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8135 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8139 Enables userThinkingEnables[] = {
\r
8140 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8141 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8142 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8143 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8144 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8145 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8146 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8147 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8148 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8149 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8150 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8151 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8152 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8153 // { IDM_Match, MF_BYCOMMAND|MF_ENABLED },
\r
8154 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8155 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8159 /*---------------------------------------------------------------------------*\
\r
8161 * Front-end interface functions exported by XBoard.
\r
8162 * Functions appear in same order as prototypes in frontend.h.
\r
8164 \*---------------------------------------------------------------------------*/
\r
8166 CheckMark(UINT item, int state)
\r
8168 if(item) CheckMenuItem(GetMenu(hwndMain), item, MF_BYCOMMAND|state);
\r
8174 static UINT prevChecked = 0;
\r
8175 static int prevPausing = 0;
\r
8178 if (pausing != prevPausing) {
\r
8179 prevPausing = pausing;
\r
8180 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8181 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8182 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8185 switch (gameMode) {
\r
8186 case BeginningOfGame:
\r
8187 if (appData.icsActive)
\r
8188 nowChecked = IDM_IcsClient;
\r
8189 else if (appData.noChessProgram)
\r
8190 nowChecked = IDM_EditGame;
\r
8192 nowChecked = IDM_MachineBlack;
\r
8194 case MachinePlaysBlack:
\r
8195 nowChecked = IDM_MachineBlack;
\r
8197 case MachinePlaysWhite:
\r
8198 nowChecked = IDM_MachineWhite;
\r
8200 case TwoMachinesPlay:
\r
8201 nowChecked = IDM_TwoMachines;
\r
8204 nowChecked = IDM_AnalysisMode;
\r
8207 nowChecked = IDM_AnalyzeFile;
\r
8210 nowChecked = IDM_EditGame;
\r
8212 case PlayFromGameFile:
\r
8213 nowChecked = IDM_LoadGame;
\r
8215 case EditPosition:
\r
8216 nowChecked = IDM_EditPosition;
\r
8219 nowChecked = IDM_Training;
\r
8221 case IcsPlayingWhite:
\r
8222 case IcsPlayingBlack:
\r
8223 case IcsObserving:
\r
8225 nowChecked = IDM_IcsClient;
\r
8232 if(prevChecked == IDM_TwoMachine) // [HGM] 'Machine Match' might have gotten disabled when stopping match
\r
8233 EnableMenuItem(GetMenu(hwndMain), IDM_Match, MF_BYCOMMAND|MF_ENABLED)
\r
8234 CheckMark(prevChecked, MF_UNCHECKED);
\r
8235 CheckMark(nowChecked, MF_CHECKED);
\r
8236 CheckMark(IDM_Match, matchMode && matchGame < appData.matchGames ? MF_CHECKED : MF_UNCHECKED);
\r
8238 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8239 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8240 MF_BYCOMMAND|MF_ENABLED);
\r
8242 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8243 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8246 prevChecked = nowChecked;
\r
8248 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8249 if (appData.icsActive) {
\r
8250 if (appData.icsEngineAnalyze) {
\r
8251 CheckMark(IDM_AnalysisMode, MF_CHECKED);
\r
8253 CheckMark(IDM_AnalysisMode, MF_UNCHECKED);
\r
8256 DisplayLogos(); // [HGM] logos: mode change could have altered logos
\r
8262 HMENU hmenu = GetMenu(hwndMain);
\r
8263 SetMenuEnables(hmenu, icsEnables);
\r
8264 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), IDM_IcsOptions,
\r
8265 MF_BYCOMMAND|MF_ENABLED);
\r
8267 if (appData.zippyPlay) {
\r
8268 SetMenuEnables(hmenu, zippyEnables);
\r
8269 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8270 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8271 MF_BYCOMMAND|MF_ENABLED);
\r
8279 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8285 HMENU hmenu = GetMenu(hwndMain);
\r
8286 SetMenuEnables(hmenu, ncpEnables);
\r
8287 DrawMenuBar(hwndMain);
\r
8293 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8297 SetTrainingModeOn()
\r
8300 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8301 for (i = 0; i < N_BUTTONS; i++) {
\r
8302 if (buttonDesc[i].hwnd != NULL)
\r
8303 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8308 VOID SetTrainingModeOff()
\r
8311 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8312 for (i = 0; i < N_BUTTONS; i++) {
\r
8313 if (buttonDesc[i].hwnd != NULL)
\r
8314 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8320 SetUserThinkingEnables()
\r
8322 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8326 SetMachineThinkingEnables()
\r
8328 HMENU hMenu = GetMenu(hwndMain);
\r
8329 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8331 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8333 if (gameMode == MachinePlaysBlack) {
\r
8334 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8335 } else if (gameMode == MachinePlaysWhite) {
\r
8336 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8337 } else if (gameMode == TwoMachinesPlay) {
\r
8338 (void)EnableMenuItem(hMenu, matchMode ? IDM_Match : IDM_TwoMachines, flags); // [HGM] match
\r
8344 DisplayTitle(char *str)
\r
8346 char title[MSG_SIZ], *host;
\r
8347 if (str[0] != NULLCHAR) {
\r
8348 safeStrCpy(title, str, sizeof(title)/sizeof(title[0]) );
\r
8349 } else if (appData.icsActive) {
\r
8350 if (appData.icsCommPort[0] != NULLCHAR)
\r
8353 host = appData.icsHost;
\r
8354 snprintf(title, MSG_SIZ, "%s: %s", szTitle, host);
\r
8355 } else if (appData.noChessProgram) {
\r
8356 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8358 safeStrCpy(title, szTitle, sizeof(title)/sizeof(title[0]) );
\r
8359 strcat(title, ": ");
\r
8360 strcat(title, first.tidy);
\r
8362 SetWindowText(hwndMain, title);
\r
8367 DisplayMessage(char *str1, char *str2)
\r
8371 int remain = MESSAGE_TEXT_MAX - 1;
\r
8374 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8375 messageText[0] = NULLCHAR;
\r
8377 len = strlen(str1);
\r
8378 if (len > remain) len = remain;
\r
8379 strncpy(messageText, str1, len);
\r
8380 messageText[len] = NULLCHAR;
\r
8383 if (*str2 && remain >= 2) {
\r
8385 strcat(messageText, " ");
\r
8388 len = strlen(str2);
\r
8389 if (len > remain) len = remain;
\r
8390 strncat(messageText, str2, len);
\r
8392 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8393 safeStrCpy(lastMsg, messageText, MSG_SIZ);
\r
8395 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8399 hdc = GetDC(hwndMain);
\r
8400 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8401 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8402 &messageRect, messageText, strlen(messageText), NULL);
\r
8403 (void) SelectObject(hdc, oldFont);
\r
8404 (void) ReleaseDC(hwndMain, hdc);
\r
8408 DisplayError(char *str, int error)
\r
8410 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8414 safeStrCpy(buf, str, sizeof(buf)/sizeof(buf[0]) );
\r
8416 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8417 NULL, error, LANG_NEUTRAL,
\r
8418 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8420 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8422 ErrorMap *em = errmap;
\r
8423 while (em->err != 0 && em->err != error) em++;
\r
8424 if (em->err != 0) {
\r
8425 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8427 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8432 ErrorPopUp(_("Error"), buf);
\r
8437 DisplayMoveError(char *str)
\r
8439 fromX = fromY = -1;
\r
8440 ClearHighlights();
\r
8441 DrawPosition(FALSE, NULL);
\r
8442 if (appData.popupMoveErrors) {
\r
8443 ErrorPopUp(_("Error"), str);
\r
8445 DisplayMessage(str, "");
\r
8446 moveErrorMessageUp = TRUE;
\r
8451 DisplayFatalError(char *str, int error, int exitStatus)
\r
8453 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8455 char *label = exitStatus ? _("Fatal Error") : _("Exiting");
\r
8458 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8459 NULL, error, LANG_NEUTRAL,
\r
8460 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8462 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, buf2);
\r
8464 ErrorMap *em = errmap;
\r
8465 while (em->err != 0 && em->err != error) em++;
\r
8466 if (em->err != 0) {
\r
8467 snprintf(buf, 2*MSG_SIZ, "%s:\n%s", str, em->msg);
\r
8469 snprintf(buf, 2*MSG_SIZ, "%s:\nError code %d", str, error);
\r
8474 if (appData.debugMode) {
\r
8475 fprintf(debugFP, "%s: %s\n", label, str);
\r
8477 if (appData.popupExitMessage) {
\r
8478 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8479 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8481 ExitEvent(exitStatus);
\r
8486 DisplayInformation(char *str)
\r
8488 (void) MessageBox(hwndMain, str, _("Information"), MB_OK|MB_ICONINFORMATION);
\r
8493 DisplayNote(char *str)
\r
8495 ErrorPopUp(_("Note"), str);
\r
8500 char *title, *question, *replyPrefix;
\r
8505 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8507 static QuestionParams *qp;
\r
8508 char reply[MSG_SIZ];
\r
8511 switch (message) {
\r
8512 case WM_INITDIALOG:
\r
8513 qp = (QuestionParams *) lParam;
\r
8514 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8515 Translate(hDlg, DLG_Question);
\r
8516 SetWindowText(hDlg, qp->title);
\r
8517 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8518 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8522 switch (LOWORD(wParam)) {
\r
8524 safeStrCpy(reply, qp->replyPrefix, sizeof(reply)/sizeof(reply[0]) );
\r
8525 if (*reply) strcat(reply, " ");
\r
8526 len = strlen(reply);
\r
8527 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8528 strcat(reply, "\n");
\r
8529 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8530 EndDialog(hDlg, TRUE);
\r
8531 if (err) DisplayFatalError(_("Error writing to chess program"), err, 1);
\r
8534 EndDialog(hDlg, FALSE);
\r
8545 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8547 QuestionParams qp;
\r
8551 qp.question = question;
\r
8552 qp.replyPrefix = replyPrefix;
\r
8554 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8555 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8556 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8557 FreeProcInstance(lpProc);
\r
8560 /* [AS] Pick FRC position */
\r
8561 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8563 static int * lpIndexFRC;
\r
8569 case WM_INITDIALOG:
\r
8570 lpIndexFRC = (int *) lParam;
\r
8572 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8573 Translate(hDlg, DLG_NewGameFRC);
\r
8575 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8576 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8577 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8578 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8583 switch( LOWORD(wParam) ) {
\r
8585 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8586 EndDialog( hDlg, 0 );
\r
8587 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8590 EndDialog( hDlg, 1 );
\r
8592 case IDC_NFG_Edit:
\r
8593 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8594 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8596 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8599 case IDC_NFG_Random:
\r
8600 snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8601 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8614 int index = appData.defaultFrcPosition;
\r
8615 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8617 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8619 if( result == 0 ) {
\r
8620 appData.defaultFrcPosition = index;
\r
8626 /* [AS] Game list options. Refactored by HGM */
\r
8628 HWND gameListOptionsDialog;
\r
8630 // low-level front-end: clear text edit / list widget
\r
8635 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8638 // low-level front-end: clear text edit / list widget
\r
8640 GLT_DeSelectList()
\r
8642 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8645 // low-level front-end: append line to text edit / list widget
\r
8647 GLT_AddToList( char *name )
\r
8650 SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) name );
\r
8654 // low-level front-end: get line from text edit / list widget
\r
8656 GLT_GetFromList( int index, char *name )
\r
8659 if( SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR )
\r
8665 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8667 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8668 int idx2 = idx1 + delta;
\r
8669 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8671 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8674 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8675 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8676 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8677 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8681 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8685 case WM_INITDIALOG:
\r
8686 gameListOptionsDialog = hDlg; // [HGM] pass through global to keep out off back-end
\r
8688 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8689 Translate(hDlg, DLG_GameListOptions);
\r
8691 /* Initialize list */
\r
8692 GLT_TagsToList( lpUserGLT );
\r
8694 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8699 switch( LOWORD(wParam) ) {
\r
8702 EndDialog( hDlg, 0 );
\r
8705 EndDialog( hDlg, 1 );
\r
8708 case IDC_GLT_Default:
\r
8709 GLT_TagsToList( GLT_DEFAULT_TAGS );
\r
8712 case IDC_GLT_Restore:
\r
8713 GLT_TagsToList( appData.gameListTags );
\r
8717 GLT_MoveSelection( hDlg, -1 );
\r
8720 case IDC_GLT_Down:
\r
8721 GLT_MoveSelection( hDlg, +1 );
\r
8731 int GameListOptions()
\r
8734 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8736 safeStrCpy( lpUserGLT, appData.gameListTags ,LPUSERGLT_SIZE );
\r
8738 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)lpUserGLT );
\r
8740 if( result == 0 ) {
\r
8741 char *oldTags = appData.gameListTags;
\r
8742 /* [AS] Memory leak here! */
\r
8743 appData.gameListTags = strdup( lpUserGLT );
\r
8744 if(strcmp(oldTags, appData.gameListTags)) // [HGM] redo Game List when we changed something
\r
8745 GameListToListBox(NULL, TRUE, ".", NULL, FALSE, FALSE); // "." as filter is kludge to select all
\r
8752 DisplayIcsInteractionTitle(char *str)
\r
8754 char consoleTitle[MSG_SIZ];
\r
8756 snprintf(consoleTitle, MSG_SIZ, "%s: %s", szConsoleTitle, str);
\r
8757 SetWindowText(hwndConsole, consoleTitle);
\r
8759 if(appData.chatBoxes) { // [HGM] chat: open chat boxes
\r
8760 char buf[MSG_SIZ], *p = buf, *q;
\r
8761 safeStrCpy(buf, appData.chatBoxes, sizeof(buf)/sizeof(buf[0]) );
\r
8763 q = strchr(p, ';');
\r
8765 if(*p) ChatPopUp(p);
\r
8769 SetActiveWindow(hwndMain);
\r
8773 DrawPosition(int fullRedraw, Board board)
\r
8775 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8778 void NotifyFrontendLogin()
\r
8781 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8787 fromX = fromY = -1;
\r
8788 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8789 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8790 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8791 dragInfo.lastpos = dragInfo.pos;
\r
8792 dragInfo.start.x = dragInfo.start.y = -1;
\r
8793 dragInfo.from = dragInfo.start;
\r
8795 DrawPosition(TRUE, NULL);
\r
8802 CommentPopUp(char *title, char *str)
\r
8804 HWND hwnd = GetActiveWindow();
\r
8805 EitherCommentPopUp(currentMove, title, str, FALSE); // [HGM] vari: fake move index, rather than 0
\r
8807 SetActiveWindow(hwnd);
\r
8811 CommentPopDown(void)
\r
8813 CheckMenuItem(GetMenu(hwndMain), IDM_Comment, MF_UNCHECKED);
\r
8814 if (commentDialog) {
\r
8815 ShowWindow(commentDialog, SW_HIDE);
\r
8817 commentUp = FALSE;
\r
8821 EditCommentPopUp(int index, char *title, char *str)
\r
8823 EitherCommentPopUp(index, title, str, TRUE);
\r
8830 MyPlaySound(&sounds[(int)SoundRoar]);
\r
8837 MyPlaySound(&sounds[(int)SoundMove]);
\r
8840 VOID PlayIcsWinSound()
\r
8842 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8845 VOID PlayIcsLossSound()
\r
8847 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8850 VOID PlayIcsDrawSound()
\r
8852 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8855 VOID PlayIcsUnfinishedSound()
\r
8857 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8863 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8869 MyPlaySound(&textAttribs[ColorTell].sound);
\r
8877 consoleEcho = TRUE;
\r
8878 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8879 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8880 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8889 consoleEcho = FALSE;
\r
8890 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8891 /* This works OK: set text and background both to the same color */
\r
8893 cf.crTextColor = COLOR_ECHOOFF;
\r
8894 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8895 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8898 /* No Raw()...? */
\r
8900 void Colorize(ColorClass cc, int continuation)
\r
8902 currentColorClass = cc;
\r
8903 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8904 consoleCF.crTextColor = textAttribs[cc].color;
\r
8905 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8906 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8912 static char buf[MSG_SIZ];
\r
8913 DWORD bufsiz = MSG_SIZ;
\r
8915 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
8916 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
8918 if (!GetUserName(buf, &bufsiz)) {
\r
8919 /*DisplayError("Error getting user name", GetLastError());*/
\r
8920 safeStrCpy(buf, _("User"), sizeof(buf)/sizeof(buf[0]) );
\r
8928 static char buf[MSG_SIZ];
\r
8929 DWORD bufsiz = MSG_SIZ;
\r
8931 if (!GetComputerName(buf, &bufsiz)) {
\r
8932 /*DisplayError("Error getting host name", GetLastError());*/
\r
8933 safeStrCpy(buf, _("Unknown"), sizeof(buf)/sizeof(buf[0]) );
\r
8940 ClockTimerRunning()
\r
8942 return clockTimerEvent != 0;
\r
8948 if (clockTimerEvent == 0) return FALSE;
\r
8949 KillTimer(hwndMain, clockTimerEvent);
\r
8950 clockTimerEvent = 0;
\r
8955 StartClockTimer(long millisec)
\r
8957 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8958 (UINT) millisec, NULL);
\r
8962 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8965 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8967 if(appData.noGUI) return;
\r
8968 hdc = GetDC(hwndMain);
\r
8969 if (!IsIconic(hwndMain)) {
\r
8970 DisplayAClock(hdc, timeRemaining, highlight,
\r
8971 flipClock ? &blackRect : &whiteRect, _("White"), flag);
\r
8973 if (highlight && iconCurrent == iconBlack) {
\r
8974 iconCurrent = iconWhite;
\r
8975 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8976 if (IsIconic(hwndMain)) {
\r
8977 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8980 (void) ReleaseDC(hwndMain, hdc);
\r
8982 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8986 DisplayBlackClock(long timeRemaining, int highlight)
\r
8989 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8992 if(appData.noGUI) return;
\r
8993 hdc = GetDC(hwndMain);
\r
8994 if (!IsIconic(hwndMain)) {
\r
8995 DisplayAClock(hdc, timeRemaining, highlight,
\r
8996 flipClock ? &whiteRect : &blackRect, _("Black"), flag);
\r
8998 if (highlight && iconCurrent == iconWhite) {
\r
8999 iconCurrent = iconBlack;
\r
9000 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9001 if (IsIconic(hwndMain)) {
\r
9002 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9005 (void) ReleaseDC(hwndMain, hdc);
\r
9007 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9012 LoadGameTimerRunning()
\r
9014 return loadGameTimerEvent != 0;
\r
9018 StopLoadGameTimer()
\r
9020 if (loadGameTimerEvent == 0) return FALSE;
\r
9021 KillTimer(hwndMain, loadGameTimerEvent);
\r
9022 loadGameTimerEvent = 0;
\r
9027 StartLoadGameTimer(long millisec)
\r
9029 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9030 (UINT) millisec, NULL);
\r
9038 char fileTitle[MSG_SIZ];
\r
9040 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9041 f = OpenFileDialog(hwndMain, "a", defName,
\r
9042 appData.oldSaveStyle ? "gam" : "pgn",
\r
9044 _("Save Game to File"), NULL, fileTitle, NULL);
\r
9046 SaveGame(f, 0, "");
\r
9053 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9055 if (delayedTimerEvent != 0) {
\r
9056 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9057 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9059 KillTimer(hwndMain, delayedTimerEvent);
\r
9060 delayedTimerEvent = 0;
\r
9061 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9062 delayedTimerCallback();
\r
9064 delayedTimerCallback = cb;
\r
9065 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9066 (UINT) millisec, NULL);
\r
9069 DelayedEventCallback
\r
9072 if (delayedTimerEvent) {
\r
9073 return delayedTimerCallback;
\r
9080 CancelDelayedEvent()
\r
9082 if (delayedTimerEvent) {
\r
9083 KillTimer(hwndMain, delayedTimerEvent);
\r
9084 delayedTimerEvent = 0;
\r
9088 DWORD GetWin32Priority(int nice)
\r
9089 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9091 REALTIME_PRIORITY_CLASS 0x00000100
\r
9092 HIGH_PRIORITY_CLASS 0x00000080
\r
9093 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9094 NORMAL_PRIORITY_CLASS 0x00000020
\r
9095 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9096 IDLE_PRIORITY_CLASS 0x00000040
\r
9098 if (nice < -15) return 0x00000080;
\r
9099 if (nice < 0) return 0x00008000;
\r
9100 if (nice == 0) return 0x00000020;
\r
9101 if (nice < 15) return 0x00004000;
\r
9102 return 0x00000040;
\r
9105 void RunCommand(char *cmdLine)
\r
9107 /* Now create the child process. */
\r
9108 STARTUPINFO siStartInfo;
\r
9109 PROCESS_INFORMATION piProcInfo;
\r
9111 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9112 siStartInfo.lpReserved = NULL;
\r
9113 siStartInfo.lpDesktop = NULL;
\r
9114 siStartInfo.lpTitle = NULL;
\r
9115 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9116 siStartInfo.cbReserved2 = 0;
\r
9117 siStartInfo.lpReserved2 = NULL;
\r
9118 siStartInfo.hStdInput = NULL;
\r
9119 siStartInfo.hStdOutput = NULL;
\r
9120 siStartInfo.hStdError = NULL;
\r
9122 CreateProcess(NULL,
\r
9123 cmdLine, /* command line */
\r
9124 NULL, /* process security attributes */
\r
9125 NULL, /* primary thread security attrs */
\r
9126 TRUE, /* handles are inherited */
\r
9127 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9128 NULL, /* use parent's environment */
\r
9130 &siStartInfo, /* STARTUPINFO pointer */
\r
9131 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9133 CloseHandle(piProcInfo.hThread);
\r
9136 /* Start a child process running the given program.
\r
9137 The process's standard output can be read from "from", and its
\r
9138 standard input can be written to "to".
\r
9139 Exit with fatal error if anything goes wrong.
\r
9140 Returns an opaque pointer that can be used to destroy the process
\r
9144 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9146 #define BUFSIZE 4096
\r
9148 HANDLE hChildStdinRd, hChildStdinWr,
\r
9149 hChildStdoutRd, hChildStdoutWr;
\r
9150 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9151 SECURITY_ATTRIBUTES saAttr;
\r
9153 PROCESS_INFORMATION piProcInfo;
\r
9154 STARTUPINFO siStartInfo;
\r
9156 char buf[MSG_SIZ];
\r
9159 if (appData.debugMode) {
\r
9160 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9165 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9166 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9167 saAttr.bInheritHandle = TRUE;
\r
9168 saAttr.lpSecurityDescriptor = NULL;
\r
9171 * The steps for redirecting child's STDOUT:
\r
9172 * 1. Create anonymous pipe to be STDOUT for child.
\r
9173 * 2. Create a noninheritable duplicate of read handle,
\r
9174 * and close the inheritable read handle.
\r
9177 /* Create a pipe for the child's STDOUT. */
\r
9178 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9179 return GetLastError();
\r
9182 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9183 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9184 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9185 FALSE, /* not inherited */
\r
9186 DUPLICATE_SAME_ACCESS);
\r
9188 return GetLastError();
\r
9190 CloseHandle(hChildStdoutRd);
\r
9193 * The steps for redirecting child's STDIN:
\r
9194 * 1. Create anonymous pipe to be STDIN for child.
\r
9195 * 2. Create a noninheritable duplicate of write handle,
\r
9196 * and close the inheritable write handle.
\r
9199 /* Create a pipe for the child's STDIN. */
\r
9200 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9201 return GetLastError();
\r
9204 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9205 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9206 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9207 FALSE, /* not inherited */
\r
9208 DUPLICATE_SAME_ACCESS);
\r
9210 return GetLastError();
\r
9212 CloseHandle(hChildStdinWr);
\r
9214 /* Arrange to (1) look in dir for the child .exe file, and
\r
9215 * (2) have dir be the child's working directory. Interpret
\r
9216 * dir relative to the directory WinBoard loaded from. */
\r
9217 GetCurrentDirectory(MSG_SIZ, buf);
\r
9218 SetCurrentDirectory(installDir);
\r
9219 SetCurrentDirectory(dir);
\r
9221 /* Now create the child process. */
\r
9223 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9224 siStartInfo.lpReserved = NULL;
\r
9225 siStartInfo.lpDesktop = NULL;
\r
9226 siStartInfo.lpTitle = NULL;
\r
9227 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9228 siStartInfo.cbReserved2 = 0;
\r
9229 siStartInfo.lpReserved2 = NULL;
\r
9230 siStartInfo.hStdInput = hChildStdinRd;
\r
9231 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9232 siStartInfo.hStdError = hChildStdoutWr;
\r
9234 fSuccess = CreateProcess(NULL,
\r
9235 cmdLine, /* command line */
\r
9236 NULL, /* process security attributes */
\r
9237 NULL, /* primary thread security attrs */
\r
9238 TRUE, /* handles are inherited */
\r
9239 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9240 NULL, /* use parent's environment */
\r
9242 &siStartInfo, /* STARTUPINFO pointer */
\r
9243 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9245 err = GetLastError();
\r
9246 SetCurrentDirectory(buf); /* return to prev directory */
\r
9251 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9252 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9253 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9256 /* Close the handles we don't need in the parent */
\r
9257 CloseHandle(piProcInfo.hThread);
\r
9258 CloseHandle(hChildStdinRd);
\r
9259 CloseHandle(hChildStdoutWr);
\r
9261 /* Prepare return value */
\r
9262 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9263 cp->kind = CPReal;
\r
9264 cp->hProcess = piProcInfo.hProcess;
\r
9265 cp->pid = piProcInfo.dwProcessId;
\r
9266 cp->hFrom = hChildStdoutRdDup;
\r
9267 cp->hTo = hChildStdinWrDup;
\r
9269 *pr = (void *) cp;
\r
9271 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9272 2000 where engines sometimes don't see the initial command(s)
\r
9273 from WinBoard and hang. I don't understand how that can happen,
\r
9274 but the Sleep is harmless, so I've put it in. Others have also
\r
9275 reported what may be the same problem, so hopefully this will fix
\r
9276 it for them too. */
\r
9284 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9286 ChildProc *cp; int result;
\r
9288 cp = (ChildProc *) pr;
\r
9289 if (cp == NULL) return;
\r
9291 switch (cp->kind) {
\r
9293 /* TerminateProcess is considered harmful, so... */
\r
9294 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9295 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9296 /* The following doesn't work because the chess program
\r
9297 doesn't "have the same console" as WinBoard. Maybe
\r
9298 we could arrange for this even though neither WinBoard
\r
9299 nor the chess program uses a console for stdio? */
\r
9300 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9302 /* [AS] Special termination modes for misbehaving programs... */
\r
9303 if( signal & 8 ) {
\r
9304 result = TerminateProcess( cp->hProcess, 0 );
\r
9306 if ( appData.debugMode) {
\r
9307 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9310 else if( signal & 4 ) {
\r
9311 DWORD dw = WaitForSingleObject( cp->hProcess, appData.delayAfterQuit*1000 + 50 ); // Wait 3 seconds at most
\r
9313 if( dw != WAIT_OBJECT_0 ) {
\r
9314 result = TerminateProcess( cp->hProcess, 0 );
\r
9316 if ( appData.debugMode) {
\r
9317 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9323 CloseHandle(cp->hProcess);
\r
9327 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9331 closesocket(cp->sock);
\r
9336 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9337 closesocket(cp->sock);
\r
9338 closesocket(cp->sock2);
\r
9346 InterruptChildProcess(ProcRef pr)
\r
9350 cp = (ChildProc *) pr;
\r
9351 if (cp == NULL) return;
\r
9352 switch (cp->kind) {
\r
9354 /* The following doesn't work because the chess program
\r
9355 doesn't "have the same console" as WinBoard. Maybe
\r
9356 we could arrange for this even though neither WinBoard
\r
9357 nor the chess program uses a console for stdio */
\r
9358 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9363 /* Can't interrupt */
\r
9367 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9374 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9376 char cmdLine[MSG_SIZ];
\r
9378 if (port[0] == NULLCHAR) {
\r
9379 snprintf(cmdLine, MSG_SIZ, "%s %s", appData.telnetProgram, host);
\r
9381 snprintf(cmdLine, MSG_SIZ, "%s %s %s", appData.telnetProgram, host, port);
\r
9383 return StartChildProcess(cmdLine, "", pr);
\r
9387 /* Code to open TCP sockets */
\r
9390 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9396 struct sockaddr_in sa, mysa;
\r
9397 struct hostent FAR *hp;
\r
9398 unsigned short uport;
\r
9399 WORD wVersionRequested;
\r
9402 /* Initialize socket DLL */
\r
9403 wVersionRequested = MAKEWORD(1, 1);
\r
9404 err = WSAStartup(wVersionRequested, &wsaData);
\r
9405 if (err != 0) return err;
\r
9408 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9409 err = WSAGetLastError();
\r
9414 /* Bind local address using (mostly) don't-care values.
\r
9416 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9417 mysa.sin_family = AF_INET;
\r
9418 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9419 uport = (unsigned short) 0;
\r
9420 mysa.sin_port = htons(uport);
\r
9421 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9422 == SOCKET_ERROR) {
\r
9423 err = WSAGetLastError();
\r
9428 /* Resolve remote host name */
\r
9429 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9430 if (!(hp = gethostbyname(host))) {
\r
9431 unsigned int b0, b1, b2, b3;
\r
9433 err = WSAGetLastError();
\r
9435 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9436 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9437 hp->h_addrtype = AF_INET;
\r
9439 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9440 hp->h_addr_list[0] = (char *) malloc(4);
\r
9441 hp->h_addr_list[0][0] = (char) b0;
\r
9442 hp->h_addr_list[0][1] = (char) b1;
\r
9443 hp->h_addr_list[0][2] = (char) b2;
\r
9444 hp->h_addr_list[0][3] = (char) b3;
\r
9450 sa.sin_family = hp->h_addrtype;
\r
9451 uport = (unsigned short) atoi(port);
\r
9452 sa.sin_port = htons(uport);
\r
9453 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9455 /* Make connection */
\r
9456 if (connect(s, (struct sockaddr *) &sa,
\r
9457 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9458 err = WSAGetLastError();
\r
9463 /* Prepare return value */
\r
9464 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9465 cp->kind = CPSock;
\r
9467 *pr = (ProcRef *) cp;
\r
9473 OpenCommPort(char *name, ProcRef *pr)
\r
9478 char fullname[MSG_SIZ];
\r
9480 if (*name != '\\')
\r
9481 snprintf(fullname, MSG_SIZ, "\\\\.\\%s", name);
\r
9483 safeStrCpy(fullname, name, sizeof(fullname)/sizeof(fullname[0]) );
\r
9485 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9486 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9487 if (h == (HANDLE) -1) {
\r
9488 return GetLastError();
\r
9492 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9494 /* Accumulate characters until a 100ms pause, then parse */
\r
9495 ct.ReadIntervalTimeout = 100;
\r
9496 ct.ReadTotalTimeoutMultiplier = 0;
\r
9497 ct.ReadTotalTimeoutConstant = 0;
\r
9498 ct.WriteTotalTimeoutMultiplier = 0;
\r
9499 ct.WriteTotalTimeoutConstant = 0;
\r
9500 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9502 /* Prepare return value */
\r
9503 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9504 cp->kind = CPComm;
\r
9507 *pr = (ProcRef *) cp;
\r
9513 OpenLoopback(ProcRef *pr)
\r
9515 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9521 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9526 struct sockaddr_in sa, mysa;
\r
9527 struct hostent FAR *hp;
\r
9528 unsigned short uport;
\r
9529 WORD wVersionRequested;
\r
9532 char stderrPortStr[MSG_SIZ];
\r
9534 /* Initialize socket DLL */
\r
9535 wVersionRequested = MAKEWORD(1, 1);
\r
9536 err = WSAStartup(wVersionRequested, &wsaData);
\r
9537 if (err != 0) return err;
\r
9539 /* Resolve remote host name */
\r
9540 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9541 if (!(hp = gethostbyname(host))) {
\r
9542 unsigned int b0, b1, b2, b3;
\r
9544 err = WSAGetLastError();
\r
9546 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9547 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9548 hp->h_addrtype = AF_INET;
\r
9550 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9551 hp->h_addr_list[0] = (char *) malloc(4);
\r
9552 hp->h_addr_list[0][0] = (char) b0;
\r
9553 hp->h_addr_list[0][1] = (char) b1;
\r
9554 hp->h_addr_list[0][2] = (char) b2;
\r
9555 hp->h_addr_list[0][3] = (char) b3;
\r
9561 sa.sin_family = hp->h_addrtype;
\r
9562 uport = (unsigned short) 514;
\r
9563 sa.sin_port = htons(uport);
\r
9564 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9566 /* Bind local socket to unused "privileged" port address
\r
9568 s = INVALID_SOCKET;
\r
9569 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9570 mysa.sin_family = AF_INET;
\r
9571 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9572 for (fromPort = 1023;; fromPort--) {
\r
9573 if (fromPort < 0) {
\r
9575 return WSAEADDRINUSE;
\r
9577 if (s == INVALID_SOCKET) {
\r
9578 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9579 err = WSAGetLastError();
\r
9584 uport = (unsigned short) fromPort;
\r
9585 mysa.sin_port = htons(uport);
\r
9586 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9587 == SOCKET_ERROR) {
\r
9588 err = WSAGetLastError();
\r
9589 if (err == WSAEADDRINUSE) continue;
\r
9593 if (connect(s, (struct sockaddr *) &sa,
\r
9594 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9595 err = WSAGetLastError();
\r
9596 if (err == WSAEADDRINUSE) {
\r
9607 /* Bind stderr local socket to unused "privileged" port address
\r
9609 s2 = INVALID_SOCKET;
\r
9610 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9611 mysa.sin_family = AF_INET;
\r
9612 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9613 for (fromPort = 1023;; fromPort--) {
\r
9614 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9615 if (fromPort < 0) {
\r
9616 (void) closesocket(s);
\r
9618 return WSAEADDRINUSE;
\r
9620 if (s2 == INVALID_SOCKET) {
\r
9621 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9622 err = WSAGetLastError();
\r
9628 uport = (unsigned short) fromPort;
\r
9629 mysa.sin_port = htons(uport);
\r
9630 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9631 == SOCKET_ERROR) {
\r
9632 err = WSAGetLastError();
\r
9633 if (err == WSAEADDRINUSE) continue;
\r
9634 (void) closesocket(s);
\r
9638 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9639 err = WSAGetLastError();
\r
9640 if (err == WSAEADDRINUSE) {
\r
9642 s2 = INVALID_SOCKET;
\r
9645 (void) closesocket(s);
\r
9646 (void) closesocket(s2);
\r
9652 prevStderrPort = fromPort; // remember port used
\r
9653 snprintf(stderrPortStr, MSG_SIZ, "%d", fromPort);
\r
9655 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9656 err = WSAGetLastError();
\r
9657 (void) closesocket(s);
\r
9658 (void) closesocket(s2);
\r
9663 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9664 err = WSAGetLastError();
\r
9665 (void) closesocket(s);
\r
9666 (void) closesocket(s2);
\r
9670 if (*user == NULLCHAR) user = UserName();
\r
9671 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9672 err = WSAGetLastError();
\r
9673 (void) closesocket(s);
\r
9674 (void) closesocket(s2);
\r
9678 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9679 err = WSAGetLastError();
\r
9680 (void) closesocket(s);
\r
9681 (void) closesocket(s2);
\r
9686 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9687 err = WSAGetLastError();
\r
9688 (void) closesocket(s);
\r
9689 (void) closesocket(s2);
\r
9693 (void) closesocket(s2); /* Stop listening */
\r
9695 /* Prepare return value */
\r
9696 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9697 cp->kind = CPRcmd;
\r
9700 *pr = (ProcRef *) cp;
\r
9707 AddInputSource(ProcRef pr, int lineByLine,
\r
9708 InputCallback func, VOIDSTAR closure)
\r
9710 InputSource *is, *is2 = NULL;
\r
9711 ChildProc *cp = (ChildProc *) pr;
\r
9713 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9714 is->lineByLine = lineByLine;
\r
9716 is->closure = closure;
\r
9717 is->second = NULL;
\r
9718 is->next = is->buf;
\r
9719 if (pr == NoProc) {
\r
9720 is->kind = CPReal;
\r
9721 consoleInputSource = is;
\r
9723 is->kind = cp->kind;
\r
9725 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9726 we create all threads suspended so that the is->hThread variable can be
\r
9727 safely assigned, then let the threads start with ResumeThread.
\r
9729 switch (cp->kind) {
\r
9731 is->hFile = cp->hFrom;
\r
9732 cp->hFrom = NULL; /* now owned by InputThread */
\r
9734 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9735 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9739 is->hFile = cp->hFrom;
\r
9740 cp->hFrom = NULL; /* now owned by InputThread */
\r
9742 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9743 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9747 is->sock = cp->sock;
\r
9749 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9750 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9754 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9756 is->sock = cp->sock;
\r
9758 is2->sock = cp->sock2;
\r
9759 is2->second = is2;
\r
9761 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9762 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9764 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9765 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9769 if( is->hThread != NULL ) {
\r
9770 ResumeThread( is->hThread );
\r
9773 if( is2 != NULL && is2->hThread != NULL ) {
\r
9774 ResumeThread( is2->hThread );
\r
9778 return (InputSourceRef) is;
\r
9782 RemoveInputSource(InputSourceRef isr)
\r
9786 is = (InputSource *) isr;
\r
9787 is->hThread = NULL; /* tell thread to stop */
\r
9788 CloseHandle(is->hThread);
\r
9789 if (is->second != NULL) {
\r
9790 is->second->hThread = NULL;
\r
9791 CloseHandle(is->second->hThread);
\r
9795 int no_wrap(char *message, int count)
\r
9797 ConsoleOutput(message, count, FALSE);
\r
9802 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9805 int outCount = SOCKET_ERROR;
\r
9806 ChildProc *cp = (ChildProc *) pr;
\r
9807 static OVERLAPPED ovl;
\r
9809 static int line = 0;
\r
9813 if (appData.noJoin || !appData.useInternalWrap)
\r
9814 return no_wrap(message, count);
\r
9817 int width = get_term_width();
\r
9818 int len = wrap(NULL, message, count, width, &line);
\r
9819 char *msg = malloc(len);
\r
9823 return no_wrap(message, count);
\r
9826 dbgchk = wrap(msg, message, count, width, &line);
\r
9827 if (dbgchk != len && appData.debugMode)
\r
9828 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
9829 ConsoleOutput(msg, len, FALSE);
\r
9836 if (ovl.hEvent == NULL) {
\r
9837 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9839 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9841 switch (cp->kind) {
\r
9844 outCount = send(cp->sock, message, count, 0);
\r
9845 if (outCount == SOCKET_ERROR) {
\r
9846 *outError = WSAGetLastError();
\r
9848 *outError = NO_ERROR;
\r
9853 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9854 &dOutCount, NULL)) {
\r
9855 *outError = NO_ERROR;
\r
9856 outCount = (int) dOutCount;
\r
9858 *outError = GetLastError();
\r
9863 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9864 &dOutCount, &ovl);
\r
9865 if (*outError == NO_ERROR) {
\r
9866 outCount = (int) dOutCount;
\r
9876 if(n != 0) Sleep(n);
\r
9880 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9883 /* Ignore delay, not implemented for WinBoard */
\r
9884 return OutputToProcess(pr, message, count, outError);
\r
9889 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9890 char *buf, int count, int error)
\r
9892 DisplayFatalError(_("Not implemented"), 0, 1);
\r
9895 /* see wgamelist.c for Game List functions */
\r
9896 /* see wedittags.c for Edit Tags functions */
\r
9903 char buf[MSG_SIZ];
\r
9906 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9907 f = fopen(buf, "r");
\r
9909 ProcessICSInitScript(f);
\r
9919 StartAnalysisClock()
\r
9921 if (analysisTimerEvent) return;
\r
9922 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9923 (UINT) 2000, NULL);
\r
9927 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9929 highlightInfo.sq[0].x = fromX;
\r
9930 highlightInfo.sq[0].y = fromY;
\r
9931 highlightInfo.sq[1].x = toX;
\r
9932 highlightInfo.sq[1].y = toY;
\r
9938 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9939 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9943 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9945 premoveHighlightInfo.sq[0].x = fromX;
\r
9946 premoveHighlightInfo.sq[0].y = fromY;
\r
9947 premoveHighlightInfo.sq[1].x = toX;
\r
9948 premoveHighlightInfo.sq[1].y = toY;
\r
9952 ClearPremoveHighlights()
\r
9954 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9955 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9959 ShutDownFrontEnd()
\r
9961 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9962 DeleteClipboardTempFiles();
\r
9968 if (IsIconic(hwndMain))
\r
9969 ShowWindow(hwndMain, SW_RESTORE);
\r
9971 SetActiveWindow(hwndMain);
\r
9975 * Prototypes for animation support routines
\r
9977 static void ScreenSquare(int column, int row, POINT * pt);
\r
9978 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9979 POINT frames[], int * nFrames);
\r
9985 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
\r
9986 { // [HGM] atomic: animate blast wave
\r
9989 explodeInfo.fromX = fromX;
\r
9990 explodeInfo.fromY = fromY;
\r
9991 explodeInfo.toX = toX;
\r
9992 explodeInfo.toY = toY;
\r
9993 for(i=1; i<4*kFactor; i++) {
\r
9994 explodeInfo.radius = (i*180)/(4*kFactor-1);
\r
9995 DrawPosition(FALSE, board);
\r
9996 Sleep(appData.animSpeed);
\r
9998 explodeInfo.radius = 0;
\r
9999 DrawPosition(TRUE, board);
\r
10003 AnimateMove(board, fromX, fromY, toX, toY)
\r
10010 ChessSquare piece;
\r
10011 int x = toX, y = toY;
\r
10012 POINT start, finish, mid;
\r
10013 POINT frames[kFactor * 2 + 1];
\r
10016 if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
\r
10018 if (!appData.animate) return;
\r
10019 if (doingSizing) return;
\r
10020 if (fromY < 0 || fromX < 0) return;
\r
10021 piece = board[fromY][fromX];
\r
10022 if (piece >= EmptySquare) return;
\r
10024 if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
\r
10028 ScreenSquare(fromX, fromY, &start);
\r
10029 ScreenSquare(toX, toY, &finish);
\r
10031 /* All moves except knight jumps move in straight line */
\r
10032 if (!(abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1)) {
\r
10033 mid.x = start.x + (finish.x - start.x) / 2;
\r
10034 mid.y = start.y + (finish.y - start.y) / 2;
\r
10036 /* Knight: make straight movement then diagonal */
\r
10037 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10038 mid.x = start.x + (finish.x - start.x) / 2;
\r
10042 mid.y = start.y + (finish.y - start.y) / 2;
\r
10046 /* Don't use as many frames for very short moves */
\r
10047 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10048 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10050 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10052 animInfo.from.x = fromX;
\r
10053 animInfo.from.y = fromY;
\r
10054 animInfo.to.x = toX;
\r
10055 animInfo.to.y = toY;
\r
10056 animInfo.lastpos = start;
\r
10057 animInfo.piece = piece;
\r
10058 for (n = 0; n < nFrames; n++) {
\r
10059 animInfo.pos = frames[n];
\r
10060 DrawPosition(FALSE, NULL);
\r
10061 animInfo.lastpos = animInfo.pos;
\r
10062 Sleep(appData.animSpeed);
\r
10064 animInfo.pos = finish;
\r
10065 DrawPosition(FALSE, NULL);
\r
10067 if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
\r
10069 animInfo.piece = EmptySquare;
\r
10070 Explode(board, fromX, fromY, toX, toY);
\r
10073 /* Convert board position to corner of screen rect and color */
\r
10076 ScreenSquare(column, row, pt)
\r
10077 int column; int row; POINT * pt;
\r
10080 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap) + border;
\r
10081 pt->y = lineGap + row * (squareSize + lineGap) + border;
\r
10083 pt->x = lineGap + column * (squareSize + lineGap) + border;
\r
10084 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap) + border;
\r
10088 /* Generate a series of frame coords from start->mid->finish.
\r
10089 The movement rate doubles until the half way point is
\r
10090 reached, then halves back down to the final destination,
\r
10091 which gives a nice slow in/out effect. The algorithmn
\r
10092 may seem to generate too many intermediates for short
\r
10093 moves, but remember that the purpose is to attract the
\r
10094 viewers attention to the piece about to be moved and
\r
10095 then to where it ends up. Too few frames would be less
\r
10099 Tween(start, mid, finish, factor, frames, nFrames)
\r
10100 POINT * start; POINT * mid;
\r
10101 POINT * finish; int factor;
\r
10102 POINT frames[]; int * nFrames;
\r
10104 int n, fraction = 1, count = 0;
\r
10106 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10107 for (n = 0; n < factor; n++)
\r
10109 for (n = 0; n < factor; n++) {
\r
10110 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10111 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10113 fraction = fraction / 2;
\r
10117 frames[count] = *mid;
\r
10120 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10122 for (n = 0; n < factor; n++) {
\r
10123 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10124 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10126 fraction = fraction * 2;
\r
10128 *nFrames = count;
\r
10132 SettingsPopUp(ChessProgramState *cps)
\r
10133 { // [HGM] wrapper needed because handles must not be passed through back-end
\r
10134 EngineOptionsPopup(savedHwnd, cps);
\r
10137 int flock(int fid, int code)
\r
10139 HANDLE hFile = (HANDLE) _get_osfhandle(fid);
\r
10141 ov.hEvent = NULL;
\r
10143 ov.OffsetHigh = 0;
\r
10145 case 1: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_SH
\r
10147 case 2: LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1024, 0, &ov); break; // LOCK_EX
\r
10148 case 3: UnlockFileEx(hFile, 0, 1024, 0, &ov); break; // LOCK_UN
\r
10149 default: return -1;
\r
10158 static char col[8][20];
\r
10159 COLORREF color = *(COLORREF *) colorVariable[n];
\r
10161 snprintf(col[i], 20, "#%02lx%02lx%02lx", color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
10166 ActivateTheme (int new)
\r
10167 { // Redo initialization of features depending on options that can occur in themes
\r
10169 if(new) InitDrawingColors();
\r
10170 fontBitmapSquareSize = 0; // request creation of new font pieces
\r
10171 InitDrawingSizes(boardSize, 0);
\r
10172 InvalidateRect(hwndMain, NULL, TRUE);
\r