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 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
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\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_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { 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) },
\r
278 { 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) },
\r
279 { 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) },
\r
280 { 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) },
\r
281 { 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) },
\r
282 { 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) },
\r
283 { 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) },
\r
284 { 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) },
\r
285 { 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) },
\r
286 { 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) },
\r
287 { 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) },
\r
288 { 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) },
\r
289 { 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) },
\r
290 { 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) },
\r
291 { 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) },
\r
292 { 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) },
\r
293 { 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) },
\r
294 { 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) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 int commentUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 int engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1395 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },
\r
1396 { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },
\r
1397 { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */
\r
1399 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1400 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1401 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1402 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1403 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1404 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1405 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1406 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1407 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1408 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1409 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1410 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1411 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1412 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1413 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1414 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1415 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1416 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1417 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1418 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1419 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1420 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1421 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1422 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1423 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1424 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1425 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1426 /* [AS] Layout stuff */
\r
1427 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1428 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1429 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1430 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1431 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1433 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1434 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1435 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1436 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1437 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1439 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1440 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1441 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1442 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1443 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1445 { NULL, ArgNone, NULL, FALSE }
\r
1449 /* Kludge for indirection files on command line */
\r
1450 char* lastIndirectionFilename;
\r
1451 ArgDescriptor argDescriptorIndirection =
\r
1452 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1456 ExitArgError(char *msg, char *badArg)
\r
1458 char buf[MSG_SIZ];
\r
1460 sprintf(buf, "%s %s", msg, badArg);
\r
1461 DisplayFatalError(buf, 0, 2);
\r
1466 ValidateInt(char *s)
\r
1469 if(*p == '-' || *p == '+') p++;
\r
1470 while(*p) if(!isdigit(*p++)) ExitArgError("Bad integer value", s);
\r
1474 /* Command line font name parser. NULL name means do nothing.
\r
1475 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1476 For backward compatibility, syntax without the colon is also
\r
1477 accepted, but font names with digits in them won't work in that case.
\r
1480 ParseFontName(char *name, MyFontParams *mfp)
\r
1483 if (name == NULL) return;
\r
1485 q = strchr(p, ':');
\r
1487 if (q - p >= sizeof(mfp->faceName))
\r
1488 ExitArgError("Font name too long:", name);
\r
1489 memcpy(mfp->faceName, p, q - p);
\r
1490 mfp->faceName[q - p] = NULLCHAR;
\r
1493 q = mfp->faceName;
\r
1494 while (*p && !isdigit(*p)) {
\r
1496 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1497 ExitArgError("Font name too long:", name);
\r
1499 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1502 if (!*p) ExitArgError("Font point size missing:", name);
\r
1503 mfp->pointSize = (float) atof(p);
\r
1504 mfp->bold = (strchr(p, 'b') != NULL);
\r
1505 mfp->italic = (strchr(p, 'i') != NULL);
\r
1506 mfp->underline = (strchr(p, 'u') != NULL);
\r
1507 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1508 mfp->charset = DEFAULT_CHARSET;
\r
1509 q = strchr(p, 'c');
\r
1511 mfp->charset = (BYTE) atoi(q+1);
\r
1514 /* Color name parser.
\r
1515 X version accepts X color names, but this one
\r
1516 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1518 ParseColorName(char *name)
\r
1520 int red, green, blue, count;
\r
1521 char buf[MSG_SIZ];
\r
1523 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1525 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1526 &red, &green, &blue);
\r
1529 sprintf(buf, "Can't parse color name %s", name);
\r
1530 DisplayError(buf, 0);
\r
1531 return RGB(0, 0, 0);
\r
1533 return PALETTERGB(red, green, blue);
\r
1537 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1539 char *e = argValue;
\r
1543 if (*e == 'b') eff |= CFE_BOLD;
\r
1544 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1545 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1546 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1547 else if (*e == '#' || isdigit(*e)) break;
\r
1551 *color = ParseColorName(e);
\r
1556 ParseBoardSize(char *name)
\r
1558 BoardSize bs = SizeTiny;
\r
1559 while (sizeInfo[bs].name != NULL) {
\r
1560 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1563 ExitArgError("Unrecognized board size value", name);
\r
1564 return bs; /* not reached */
\r
1569 StringGet(void *getClosure)
\r
1571 char **p = (char **) getClosure;
\r
1576 FileGet(void *getClosure)
\r
1579 FILE* f = (FILE*) getClosure;
\r
1582 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1589 /* Parse settings file named "name". If file found, return the
\r
1590 full name in fullname and return TRUE; else return FALSE */
\r
1592 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1596 int ok; char buf[MSG_SIZ];
\r
1598 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1599 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1600 sprintf(buf, "%s.ini", name);
\r
1601 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1604 f = fopen(fullname, "r");
\r
1606 ParseArgs(FileGet, f);
\r
1615 ParseArgs(GetFunc get, void *cl)
\r
1617 char argName[ARG_MAX];
\r
1618 char argValue[ARG_MAX];
\r
1619 ArgDescriptor *ad;
\r
1628 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1629 if (ch == NULLCHAR) break;
\r
1631 /* Comment to end of line */
\r
1633 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1635 } else if (ch == '/' || ch == '-') {
\r
1638 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1639 ch != '\n' && ch != '\t') {
\r
1645 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1646 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1648 if (ad->argName == NULL)
\r
1649 ExitArgError("Unrecognized argument", argName);
\r
1651 } else if (ch == '@') {
\r
1652 /* Indirection file */
\r
1653 ad = &argDescriptorIndirection;
\r
1656 /* Positional argument */
\r
1657 ad = &argDescriptors[posarg++];
\r
1658 strcpy(argName, ad->argName);
\r
1661 if (ad->argType == ArgTrue) {
\r
1662 *(Boolean *) ad->argLoc = TRUE;
\r
1665 if (ad->argType == ArgFalse) {
\r
1666 *(Boolean *) ad->argLoc = FALSE;
\r
1670 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1671 if (ch == NULLCHAR || ch == '\n') {
\r
1672 ExitArgError("No value provided for argument", argName);
\r
1676 // Quoting with { }. No characters have to (or can) be escaped.
\r
1677 // Thus the string cannot contain a '}' character.
\r
1697 } else if (ch == '\'' || ch == '"') {
\r
1698 // Quoting with ' ' or " ", with \ as escape character.
\r
1699 // Inconvenient for long strings that may contain Windows filenames.
\r
1716 if (ch == start) {
\r
1725 if (ad->argType == ArgFilename
\r
1726 || ad->argType == ArgSettingsFilename) {
\r
1732 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1756 for (i = 0; i < 3; i++) {
\r
1757 if (ch >= '0' && ch <= '7') {
\r
1758 octval = octval*8 + (ch - '0');
\r
1765 *q++ = (char) octval;
\r
1776 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1783 switch (ad->argType) {
\r
1785 *(int *) ad->argLoc = ValidateInt(argValue);
\r
1789 *(int *) ad->argLoc = ValidateInt(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1793 *(int *) ad->argLoc = ValidateInt(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1797 *(int *) ad->argLoc = ValidateInt(argValue);
\r
1798 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1802 *(float *) ad->argLoc = (float) atof(argValue);
\r
1807 *(char **) ad->argLoc = strdup(argValue);
\r
1810 case ArgSettingsFilename:
\r
1812 char fullname[MSG_SIZ];
\r
1813 if (ParseSettingsFile(argValue, fullname)) {
\r
1814 if (ad->argLoc != NULL) {
\r
1815 *(char **) ad->argLoc = strdup(fullname);
\r
1818 if (ad->argLoc != NULL) {
\r
1820 ExitArgError("Failed to open indirection file", argValue);
\r
1827 switch (argValue[0]) {
\r
1830 *(Boolean *) ad->argLoc = TRUE;
\r
1834 *(Boolean *) ad->argLoc = FALSE;
\r
1837 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1843 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1846 case ArgAttribs: {
\r
1847 ColorClass cc = (ColorClass)ad->argLoc;
\r
1848 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1852 case ArgBoardSize:
\r
1853 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1857 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1860 case ArgCommSettings:
\r
1861 ParseCommSettings(argValue, &dcb);
\r
1865 ExitArgError("Unrecognized argument", argValue);
\r
1874 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1876 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1877 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1880 lf->lfEscapement = 0;
\r
1881 lf->lfOrientation = 0;
\r
1882 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1883 lf->lfItalic = mfp->italic;
\r
1884 lf->lfUnderline = mfp->underline;
\r
1885 lf->lfStrikeOut = mfp->strikeout;
\r
1886 lf->lfCharSet = mfp->charset;
\r
1887 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1888 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1889 lf->lfQuality = DEFAULT_QUALITY;
\r
1890 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1891 strcpy(lf->lfFaceName, mfp->faceName);
\r
1895 CreateFontInMF(MyFont *mf)
\r
1897 LFfromMFP(&mf->lf, &mf->mfp);
\r
1898 if (mf->hf) DeleteObject(mf->hf);
\r
1899 mf->hf = CreateFontIndirect(&mf->lf);
\r
1903 SetDefaultTextAttribs()
\r
1906 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1907 ParseAttribs(&textAttribs[cc].color,
\r
1908 &textAttribs[cc].effects,
\r
1909 defaultTextAttribs[cc]);
\r
1914 SetDefaultSounds()
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 textAttribs[cc].sound.name = strdup("");
\r
1920 textAttribs[cc].sound.data = NULL;
\r
1922 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1923 sounds[sc].name = strdup("");
\r
1924 sounds[sc].data = NULL;
\r
1926 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1934 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1935 MyLoadSound(&textAttribs[cc].sound);
\r
1937 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1938 MyLoadSound(&sounds[sc]);
\r
1943 InitAppData(LPSTR lpCmdLine)
\r
1946 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1949 programName = szAppName;
\r
1951 /* Initialize to defaults */
\r
1952 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1953 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1954 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1955 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1956 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1957 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1958 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1959 SetDefaultTextAttribs();
\r
1960 SetDefaultSounds();
\r
1961 appData.movesPerSession = MOVES_PER_SESSION;
\r
1962 appData.initString = INIT_STRING;
\r
1963 appData.secondInitString = INIT_STRING;
\r
1964 appData.firstComputerString = COMPUTER_STRING;
\r
1965 appData.secondComputerString = COMPUTER_STRING;
\r
1966 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1967 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1968 appData.firstPlaysBlack = FALSE;
\r
1969 appData.noChessProgram = FALSE;
\r
1970 chessProgram = FALSE;
\r
1971 appData.firstHost = FIRST_HOST;
\r
1972 appData.secondHost = SECOND_HOST;
\r
1973 appData.firstDirectory = FIRST_DIRECTORY;
\r
1974 appData.secondDirectory = SECOND_DIRECTORY;
\r
1975 appData.bitmapDirectory = "";
\r
1976 appData.remoteShell = REMOTE_SHELL;
\r
1977 appData.remoteUser = "";
\r
1978 appData.timeDelay = TIME_DELAY;
\r
1979 appData.timeControl = TIME_CONTROL;
\r
1980 appData.timeIncrement = TIME_INCREMENT;
\r
1981 appData.icsActive = FALSE;
\r
1982 appData.icsHost = "";
\r
1983 appData.icsPort = ICS_PORT;
\r
1984 appData.icsCommPort = ICS_COMM_PORT;
\r
1985 appData.icsLogon = ICS_LOGON;
\r
1986 appData.icsHelper = "";
\r
1987 appData.useTelnet = FALSE;
\r
1988 appData.telnetProgram = TELNET_PROGRAM;
\r
1989 appData.gateway = "";
\r
1990 appData.loadGameFile = "";
\r
1991 appData.loadGameIndex = 0;
\r
1992 appData.saveGameFile = "";
\r
1993 appData.autoSaveGames = FALSE;
\r
1994 appData.loadPositionFile = "";
\r
1995 appData.loadPositionIndex = 1;
\r
1996 appData.savePositionFile = "";
\r
1997 appData.matchMode = FALSE;
\r
1998 appData.matchGames = 0;
\r
1999 appData.monoMode = FALSE;
\r
2000 appData.debugMode = FALSE;
\r
2001 appData.clockMode = TRUE;
\r
2002 boardSize = (BoardSize) -1; /* determine by screen size */
\r
2003 appData.Iconic = FALSE; /*unused*/
\r
2004 appData.searchTime = "";
\r
2005 appData.searchDepth = 0;
\r
2006 appData.showCoords = FALSE;
\r
2007 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
2008 appData.autoCallFlag = FALSE;
\r
2009 appData.flipView = FALSE;
\r
2010 appData.autoFlipView = TRUE;
\r
2011 appData.cmailGameName = "";
\r
2012 appData.alwaysPromoteToQueen = FALSE;
\r
2013 appData.oldSaveStyle = FALSE;
\r
2014 appData.quietPlay = FALSE;
\r
2015 appData.showThinking = FALSE;
\r
2016 appData.ponderNextMove = TRUE;
\r
2017 appData.periodicUpdates = TRUE;
\r
2018 appData.popupExitMessage = TRUE;
\r
2019 appData.popupMoveErrors = FALSE;
\r
2020 appData.autoObserve = FALSE;
\r
2021 appData.autoComment = FALSE;
\r
2022 appData.animate = TRUE;
\r
2023 appData.animSpeed = 10;
\r
2024 appData.animateDragging = TRUE;
\r
2025 appData.highlightLastMove = TRUE;
\r
2026 appData.getMoveList = TRUE;
\r
2027 appData.testLegality = TRUE;
\r
2028 appData.premove = TRUE;
\r
2029 appData.premoveWhite = FALSE;
\r
2030 appData.premoveWhiteText = "";
\r
2031 appData.premoveBlack = FALSE;
\r
2032 appData.premoveBlackText = "";
\r
2033 appData.icsAlarm = TRUE;
\r
2034 appData.icsAlarmTime = 5000;
\r
2035 appData.autoRaiseBoard = TRUE;
\r
2036 appData.localLineEditing = TRUE;
\r
2037 appData.colorize = TRUE;
\r
2038 appData.reuseFirst = TRUE;
\r
2039 appData.reuseSecond = TRUE;
\r
2040 appData.blindfold = FALSE;
\r
2041 appData.icsEngineAnalyze = FALSE;
\r
2042 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2043 dcb.DCBlength = sizeof(DCB);
\r
2044 dcb.BaudRate = 9600;
\r
2045 dcb.fBinary = TRUE;
\r
2046 dcb.fParity = FALSE;
\r
2047 dcb.fOutxCtsFlow = FALSE;
\r
2048 dcb.fOutxDsrFlow = FALSE;
\r
2049 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2050 dcb.fDsrSensitivity = FALSE;
\r
2051 dcb.fTXContinueOnXoff = TRUE;
\r
2052 dcb.fOutX = FALSE;
\r
2054 dcb.fNull = FALSE;
\r
2055 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2056 dcb.fAbortOnError = FALSE;
\r
2058 dcb.Parity = SPACEPARITY;
\r
2059 dcb.StopBits = ONESTOPBIT;
\r
2060 settingsFileName = SETTINGS_FILE;
\r
2061 saveSettingsOnExit = TRUE;
\r
2062 boardX = CW_USEDEFAULT;
\r
2063 boardY = CW_USEDEFAULT;
\r
2064 analysisX = CW_USEDEFAULT;
\r
2065 analysisY = CW_USEDEFAULT;
\r
2066 analysisW = CW_USEDEFAULT;
\r
2067 analysisH = CW_USEDEFAULT;
\r
2068 commentX = CW_USEDEFAULT;
\r
2069 commentY = CW_USEDEFAULT;
\r
2070 commentW = CW_USEDEFAULT;
\r
2071 commentH = CW_USEDEFAULT;
\r
2072 editTagsX = CW_USEDEFAULT;
\r
2073 editTagsY = CW_USEDEFAULT;
\r
2074 editTagsW = CW_USEDEFAULT;
\r
2075 editTagsH = CW_USEDEFAULT;
\r
2076 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2077 icsNames = ICS_NAMES;
\r
2078 firstChessProgramNames = FCP_NAMES;
\r
2079 secondChessProgramNames = SCP_NAMES;
\r
2080 appData.initialMode = "";
\r
2081 appData.variant = "normal";
\r
2082 appData.firstProtocolVersion = PROTOVER;
\r
2083 appData.secondProtocolVersion = PROTOVER;
\r
2084 appData.showButtonBar = TRUE;
\r
2086 /* [AS] New properties (see comments in header file) */
\r
2087 appData.firstScoreIsAbsolute = FALSE;
\r
2088 appData.secondScoreIsAbsolute = FALSE;
\r
2089 appData.saveExtendedInfoInPGN = FALSE;
\r
2090 appData.hideThinkingFromHuman = FALSE;
\r
2091 appData.liteBackTextureFile = "";
\r
2092 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2093 appData.darkBackTextureFile = "";
\r
2094 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2095 appData.renderPiecesWithFont = "";
\r
2096 appData.fontToPieceTable = "";
\r
2097 appData.fontBackColorWhite = 0;
\r
2098 appData.fontForeColorWhite = 0;
\r
2099 appData.fontBackColorBlack = 0;
\r
2100 appData.fontForeColorBlack = 0;
\r
2101 appData.fontPieceSize = 80;
\r
2102 appData.overrideLineGap = 1;
\r
2103 appData.adjudicateLossThreshold = 0;
\r
2104 appData.delayBeforeQuit = 0;
\r
2105 appData.delayAfterQuit = 0;
\r
2106 appData.nameOfDebugFile = "winboard.debug";
\r
2107 appData.pgnEventHeader = "Computer Chess Game";
\r
2108 appData.defaultFrcPosition = -1;
\r
2109 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2110 appData.saveOutOfBookInfo = TRUE;
\r
2111 appData.showEvalInMoveHistory = TRUE;
\r
2112 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2113 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2114 appData.highlightMoveWithArrow = FALSE;
\r
2115 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2116 appData.useStickyWindows = TRUE;
\r
2117 appData.adjudicateDrawMoves = 0;
\r
2118 appData.autoDisplayComment = TRUE;
\r
2119 appData.autoDisplayTags = TRUE;
\r
2120 appData.firstIsUCI = FALSE;
\r
2121 appData.secondIsUCI = FALSE;
\r
2122 appData.firstHasOwnBookUCI = TRUE;
\r
2123 appData.secondHasOwnBookUCI = TRUE;
\r
2124 appData.polyglotDir = "";
\r
2125 appData.usePolyglotBook = FALSE;
\r
2126 appData.polyglotBook = "";
\r
2127 appData.defaultHashSize = 64;
\r
2128 appData.defaultCacheSizeEGTB = 4;
\r
2129 appData.defaultPathEGTB = "c:\\egtb";
\r
2130 appData.firstOptions = "";
\r
2131 appData.secondOptions = "";
\r
2133 InitWindowPlacement( &wpGameList );
\r
2134 InitWindowPlacement( &wpMoveHistory );
\r
2135 InitWindowPlacement( &wpEvalGraph );
\r
2136 InitWindowPlacement( &wpEngineOutput );
\r
2137 InitWindowPlacement( &wpConsole );
\r
2139 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2140 appData.NrFiles = -1;
\r
2141 appData.NrRanks = -1;
\r
2142 appData.holdingsSize = -1;
\r
2143 appData.testClaims = FALSE;
\r
2144 appData.checkMates = FALSE;
\r
2145 appData.materialDraws= FALSE;
\r
2146 appData.trivialDraws = FALSE;
\r
2147 appData.ruleMoves = 51;
\r
2148 appData.drawRepeats = 6;
\r
2149 appData.matchPause = 10000;
\r
2150 appData.alphaRank = FALSE;
\r
2151 appData.allWhite = FALSE;
\r
2152 appData.upsideDown = FALSE;
\r
2153 appData.serverPause = 15;
\r
2154 appData.serverMovesName = NULL;
\r
2155 appData.suppressLoadMoves = FALSE;
\r
2156 appData.firstTimeOdds = 1;
\r
2157 appData.secondTimeOdds = 1;
\r
2158 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2159 appData.secondAccumulateTC = 1;
\r
2160 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2161 appData.secondNPS = -1;
\r
2162 appData.engineComments = 1;
\r
2163 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2164 appData.egtFormats = "";
\r
2167 appData.zippyTalk = ZIPPY_TALK;
\r
2168 appData.zippyPlay = ZIPPY_PLAY;
\r
2169 appData.zippyLines = ZIPPY_LINES;
\r
2170 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2171 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2172 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2173 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2174 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2175 appData.zippyUseI = ZIPPY_USE_I;
\r
2176 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2177 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2178 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2179 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2180 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2181 appData.zippyAbort = ZIPPY_ABORT;
\r
2182 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2183 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2184 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2187 /* Point font array elements to structures and
\r
2188 parse default font names */
\r
2189 for (i=0; i<NUM_FONTS; i++) {
\r
2190 for (j=0; j<NUM_SIZES; j++) {
\r
2191 font[j][i] = &fontRec[j][i];
\r
2192 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2196 /* Parse default settings file if any */
\r
2197 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2198 settingsFileName = strdup(buf);
\r
2201 /* Parse command line */
\r
2202 ParseArgs(StringGet, &lpCmdLine);
\r
2204 /* [HGM] make sure board size is acceptable */
\r
2205 if(appData.NrFiles > BOARD_SIZE ||
\r
2206 appData.NrRanks > BOARD_SIZE )
\r
2207 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2209 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2210 * with options from the command line, we now make an even higher priority
\r
2211 * overrule by WB options attached to the engine command line. This so that
\r
2212 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2215 if(appData.firstChessProgram != NULL) {
\r
2216 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2217 static char *f = "first";
\r
2218 char buf[MSG_SIZ], *q = buf;
\r
2219 if(p != NULL) { // engine command line contains WinBoard options
\r
2220 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2221 ParseArgs(StringGet, &q);
\r
2222 p[-1] = 0; // cut them offengine command line
\r
2225 // now do same for second chess program
\r
2226 if(appData.secondChessProgram != NULL) {
\r
2227 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2228 static char *s = "second";
\r
2229 char buf[MSG_SIZ], *q = buf;
\r
2230 if(p != NULL) { // engine command line contains WinBoard options
\r
2231 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2232 ParseArgs(StringGet, &q);
\r
2233 p[-1] = 0; // cut them offengine command line
\r
2238 /* Propagate options that affect others */
\r
2239 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2240 if (appData.icsActive || appData.noChessProgram) {
\r
2241 chessProgram = FALSE; /* not local chess program mode */
\r
2244 /* Open startup dialog if needed */
\r
2245 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2246 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2247 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2248 *appData.secondChessProgram == NULLCHAR))) {
\r
2251 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2252 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2253 FreeProcInstance(lpProc);
\r
2256 /* Make sure save files land in the right (?) directory */
\r
2257 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2258 appData.saveGameFile = strdup(buf);
\r
2260 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2261 appData.savePositionFile = strdup(buf);
\r
2264 /* Finish initialization for fonts and sounds */
\r
2265 for (i=0; i<NUM_FONTS; i++) {
\r
2266 for (j=0; j<NUM_SIZES; j++) {
\r
2267 CreateFontInMF(font[j][i]);
\r
2270 /* xboard, and older WinBoards, controlled the move sound with the
\r
2271 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2272 always turn the option on (so that the backend will call us),
\r
2273 then let the user turn the sound off by setting it to silence if
\r
2274 desired. To accommodate old winboard.ini files saved by old
\r
2275 versions of WinBoard, we also turn off the sound if the option
\r
2276 was initially set to false. */
\r
2277 if (!appData.ringBellAfterMoves) {
\r
2278 sounds[(int)SoundMove].name = strdup("");
\r
2279 appData.ringBellAfterMoves = TRUE;
\r
2281 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2282 SetCurrentDirectory(installDir);
\r
2284 SetCurrentDirectory(currDir);
\r
2286 p = icsTextMenuString;
\r
2287 if (p[0] == '@') {
\r
2288 FILE* f = fopen(p + 1, "r");
\r
2290 DisplayFatalError(p + 1, errno, 2);
\r
2293 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2295 buf[i] = NULLCHAR;
\r
2298 ParseIcsTextMenu(strdup(p));
\r
2305 HMENU hmenu = GetMenu(hwndMain);
\r
2307 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2308 MF_BYCOMMAND|((appData.icsActive &&
\r
2309 *appData.icsCommPort != NULLCHAR) ?
\r
2310 MF_ENABLED : MF_GRAYED));
\r
2311 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2312 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2313 MF_CHECKED : MF_UNCHECKED));
\r
2318 SaveSettings(char* name)
\r
2321 ArgDescriptor *ad;
\r
2322 WINDOWPLACEMENT wp;
\r
2323 char dir[MSG_SIZ];
\r
2325 if (!hwndMain) return;
\r
2327 GetCurrentDirectory(MSG_SIZ, dir);
\r
2328 SetCurrentDirectory(installDir);
\r
2329 f = fopen(name, "w");
\r
2330 SetCurrentDirectory(dir);
\r
2332 DisplayError(name, errno);
\r
2335 fprintf(f, ";\n");
\r
2336 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2337 fprintf(f, ";\n");
\r
2338 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2339 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2340 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2341 fprintf(f, ";\n");
\r
2343 wp.length = sizeof(WINDOWPLACEMENT);
\r
2344 GetWindowPlacement(hwndMain, &wp);
\r
2345 boardX = wp.rcNormalPosition.left;
\r
2346 boardY = wp.rcNormalPosition.top;
\r
2348 if (hwndConsole) {
\r
2349 GetWindowPlacement(hwndConsole, &wp);
\r
2350 wpConsole.x = wp.rcNormalPosition.left;
\r
2351 wpConsole.y = wp.rcNormalPosition.top;
\r
2352 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (analysisDialog) {
\r
2357 GetWindowPlacement(analysisDialog, &wp);
\r
2358 analysisX = wp.rcNormalPosition.left;
\r
2359 analysisY = wp.rcNormalPosition.top;
\r
2360 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (commentDialog) {
\r
2365 GetWindowPlacement(commentDialog, &wp);
\r
2366 commentX = wp.rcNormalPosition.left;
\r
2367 commentY = wp.rcNormalPosition.top;
\r
2368 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 if (editTagsDialog) {
\r
2373 GetWindowPlacement(editTagsDialog, &wp);
\r
2374 editTagsX = wp.rcNormalPosition.left;
\r
2375 editTagsY = wp.rcNormalPosition.top;
\r
2376 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2377 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2380 if (gameListDialog) {
\r
2381 GetWindowPlacement(gameListDialog, &wp);
\r
2382 wpGameList.x = wp.rcNormalPosition.left;
\r
2383 wpGameList.y = wp.rcNormalPosition.top;
\r
2384 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2385 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2388 /* [AS] Move history */
\r
2389 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2391 if( moveHistoryDialog ) {
\r
2392 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2393 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2394 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2395 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2396 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2399 /* [AS] Eval graph */
\r
2400 wpEvalGraph.visible = EvalGraphIsUp();
\r
2402 if( evalGraphDialog ) {
\r
2403 GetWindowPlacement(evalGraphDialog, &wp);
\r
2404 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2405 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2406 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2407 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2410 /* [AS] Engine output */
\r
2411 wpEngineOutput.visible = EngineOutputIsUp();
\r
2413 if( engineOutputDialog ) {
\r
2414 GetWindowPlacement(engineOutputDialog, &wp);
\r
2415 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2416 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2417 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2418 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2421 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2422 if (!ad->save) continue;
\r
2423 switch (ad->argType) {
\r
2426 char *p = *(char **)ad->argLoc;
\r
2427 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2428 /* Quote multiline values or \-containing values
\r
2429 with { } if possible */
\r
2430 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2432 /* Else quote with " " */
\r
2433 fprintf(f, "/%s=\"", ad->argName);
\r
2435 if (*p == '\n') fprintf(f, "\n");
\r
2436 else if (*p == '\r') fprintf(f, "\\r");
\r
2437 else if (*p == '\t') fprintf(f, "\\t");
\r
2438 else if (*p == '\b') fprintf(f, "\\b");
\r
2439 else if (*p == '\f') fprintf(f, "\\f");
\r
2440 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2441 else if (*p == '\"') fprintf(f, "\\\"");
\r
2442 else if (*p == '\\') fprintf(f, "\\\\");
\r
2446 fprintf(f, "\"\n");
\r
2452 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2455 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2458 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2461 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2464 fprintf(f, "/%s=%s\n", ad->argName,
\r
2465 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2468 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2471 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2475 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2476 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2477 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2482 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2483 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2484 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2485 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2486 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2487 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2488 (ta->effects) ? " " : "",
\r
2489 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2493 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2494 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2496 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2499 case ArgBoardSize:
\r
2500 fprintf(f, "/%s=%s\n", ad->argName,
\r
2501 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2506 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2507 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2508 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2509 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2510 ad->argName, mfp->faceName, mfp->pointSize,
\r
2511 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2512 mfp->bold ? "b" : "",
\r
2513 mfp->italic ? "i" : "",
\r
2514 mfp->underline ? "u" : "",
\r
2515 mfp->strikeout ? "s" : "",
\r
2516 (int)mfp->charset);
\r
2520 case ArgCommSettings:
\r
2521 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2523 case ArgSettingsFilename: ;
\r
2531 /*---------------------------------------------------------------------------*\
\r
2533 * GDI board drawing routines
\r
2535 \*---------------------------------------------------------------------------*/
\r
2537 /* [AS] Draw square using background texture */
\r
2538 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2543 return; /* Should never happen! */
\r
2546 SetGraphicsMode( dst, GM_ADVANCED );
\r
2553 /* X reflection */
\r
2558 x.eDx = (FLOAT) dw + dx - 1;
\r
2561 SetWorldTransform( dst, &x );
\r
2564 /* Y reflection */
\r
2570 x.eDy = (FLOAT) dh + dy - 1;
\r
2572 SetWorldTransform( dst, &x );
\r
2580 x.eDx = (FLOAT) dx;
\r
2581 x.eDy = (FLOAT) dy;
\r
2584 SetWorldTransform( dst, &x );
\r
2588 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2596 SetWorldTransform( dst, &x );
\r
2598 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2601 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2603 PM_WP = (int) WhitePawn,
\r
2604 PM_WN = (int) WhiteKnight,
\r
2605 PM_WB = (int) WhiteBishop,
\r
2606 PM_WR = (int) WhiteRook,
\r
2607 PM_WQ = (int) WhiteQueen,
\r
2608 PM_WF = (int) WhiteFerz,
\r
2609 PM_WW = (int) WhiteWazir,
\r
2610 PM_WE = (int) WhiteAlfil,
\r
2611 PM_WM = (int) WhiteMan,
\r
2612 PM_WO = (int) WhiteCannon,
\r
2613 PM_WU = (int) WhiteUnicorn,
\r
2614 PM_WH = (int) WhiteNightrider,
\r
2615 PM_WA = (int) WhiteAngel,
\r
2616 PM_WC = (int) WhiteMarshall,
\r
2617 PM_WAB = (int) WhiteCardinal,
\r
2618 PM_WD = (int) WhiteDragon,
\r
2619 PM_WL = (int) WhiteLance,
\r
2620 PM_WS = (int) WhiteCobra,
\r
2621 PM_WV = (int) WhiteFalcon,
\r
2622 PM_WSG = (int) WhiteSilver,
\r
2623 PM_WG = (int) WhiteGrasshopper,
\r
2624 PM_WK = (int) WhiteKing,
\r
2625 PM_BP = (int) BlackPawn,
\r
2626 PM_BN = (int) BlackKnight,
\r
2627 PM_BB = (int) BlackBishop,
\r
2628 PM_BR = (int) BlackRook,
\r
2629 PM_BQ = (int) BlackQueen,
\r
2630 PM_BF = (int) BlackFerz,
\r
2631 PM_BW = (int) BlackWazir,
\r
2632 PM_BE = (int) BlackAlfil,
\r
2633 PM_BM = (int) BlackMan,
\r
2634 PM_BO = (int) BlackCannon,
\r
2635 PM_BU = (int) BlackUnicorn,
\r
2636 PM_BH = (int) BlackNightrider,
\r
2637 PM_BA = (int) BlackAngel,
\r
2638 PM_BC = (int) BlackMarshall,
\r
2639 PM_BG = (int) BlackGrasshopper,
\r
2640 PM_BAB = (int) BlackCardinal,
\r
2641 PM_BD = (int) BlackDragon,
\r
2642 PM_BL = (int) BlackLance,
\r
2643 PM_BS = (int) BlackCobra,
\r
2644 PM_BV = (int) BlackFalcon,
\r
2645 PM_BSG = (int) BlackSilver,
\r
2646 PM_BK = (int) BlackKing
\r
2649 static HFONT hPieceFont = NULL;
\r
2650 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2651 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2652 static int fontBitmapSquareSize = 0;
\r
2653 static char pieceToFontChar[(int) EmptySquare] =
\r
2654 { 'p', 'n', 'b', 'r', 'q',
\r
2655 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2656 'k', 'o', 'm', 'v', 't', 'w',
\r
2657 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2660 extern BOOL SetCharTable( char *table, const char * map );
\r
2661 /* [HGM] moved to backend.c */
\r
2663 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2666 BYTE r1 = GetRValue( color );
\r
2667 BYTE g1 = GetGValue( color );
\r
2668 BYTE b1 = GetBValue( color );
\r
2674 /* Create a uniform background first */
\r
2675 hbrush = CreateSolidBrush( color );
\r
2676 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2677 FillRect( hdc, &rc, hbrush );
\r
2678 DeleteObject( hbrush );
\r
2681 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2682 int steps = squareSize / 2;
\r
2685 for( i=0; i<steps; i++ ) {
\r
2686 BYTE r = r1 - (r1-r2) * i / steps;
\r
2687 BYTE g = g1 - (g1-g2) * i / steps;
\r
2688 BYTE b = b1 - (b1-b2) * i / steps;
\r
2690 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2691 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2692 FillRect( hdc, &rc, hbrush );
\r
2693 DeleteObject(hbrush);
\r
2696 else if( mode == 2 ) {
\r
2697 /* Diagonal gradient, good more or less for every piece */
\r
2698 POINT triangle[3];
\r
2699 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2700 HBRUSH hbrush_old;
\r
2701 int steps = squareSize;
\r
2704 triangle[0].x = squareSize - steps;
\r
2705 triangle[0].y = squareSize;
\r
2706 triangle[1].x = squareSize;
\r
2707 triangle[1].y = squareSize;
\r
2708 triangle[2].x = squareSize;
\r
2709 triangle[2].y = squareSize - steps;
\r
2711 for( i=0; i<steps; i++ ) {
\r
2712 BYTE r = r1 - (r1-r2) * i / steps;
\r
2713 BYTE g = g1 - (g1-g2) * i / steps;
\r
2714 BYTE b = b1 - (b1-b2) * i / steps;
\r
2716 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2717 hbrush_old = SelectObject( hdc, hbrush );
\r
2718 Polygon( hdc, triangle, 3 );
\r
2719 SelectObject( hdc, hbrush_old );
\r
2720 DeleteObject(hbrush);
\r
2725 SelectObject( hdc, hpen );
\r
2730 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2731 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2732 piece: follow the steps as explained below.
\r
2734 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2738 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2742 int backColor = whitePieceColor;
\r
2743 int foreColor = blackPieceColor;
\r
2745 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2746 backColor = appData.fontBackColorWhite;
\r
2747 foreColor = appData.fontForeColorWhite;
\r
2749 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2750 backColor = appData.fontBackColorBlack;
\r
2751 foreColor = appData.fontForeColorBlack;
\r
2755 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2757 hbm_old = SelectObject( hdc, hbm );
\r
2761 rc.right = squareSize;
\r
2762 rc.bottom = squareSize;
\r
2764 /* Step 1: background is now black */
\r
2765 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2767 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2769 pt.x = (squareSize - sz.cx) / 2;
\r
2770 pt.y = (squareSize - sz.cy) / 2;
\r
2772 SetBkMode( hdc, TRANSPARENT );
\r
2773 SetTextColor( hdc, chroma );
\r
2774 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2775 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2777 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2778 /* Step 3: the area outside the piece is filled with white */
\r
2779 // FloodFill( hdc, 0, 0, chroma );
\r
2780 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2781 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2782 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2783 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2784 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2786 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2787 but if the start point is not inside the piece we're lost!
\r
2788 There should be a better way to do this... if we could create a region or path
\r
2789 from the fill operation we would be fine for example.
\r
2791 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2792 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2794 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2795 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2796 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2798 SelectObject( dc2, bm2 );
\r
2799 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2800 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2801 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2802 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2803 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2806 DeleteObject( bm2 );
\r
2809 SetTextColor( hdc, 0 );
\r
2811 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2812 draw the piece again in black for safety.
\r
2814 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2816 SelectObject( hdc, hbm_old );
\r
2818 if( hPieceMask[index] != NULL ) {
\r
2819 DeleteObject( hPieceMask[index] );
\r
2822 hPieceMask[index] = hbm;
\r
2825 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2827 SelectObject( hdc, hbm );
\r
2830 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2831 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2832 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2834 SelectObject( dc1, hPieceMask[index] );
\r
2835 SelectObject( dc2, bm2 );
\r
2836 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2837 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2840 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2841 the piece background and deletes (makes transparent) the rest.
\r
2842 Thanks to that mask, we are free to paint the background with the greates
\r
2843 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2844 We use this, to make gradients and give the pieces a "roundish" look.
\r
2846 SetPieceBackground( hdc, backColor, 2 );
\r
2847 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2851 DeleteObject( bm2 );
\r
2854 SetTextColor( hdc, foreColor );
\r
2855 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2857 SelectObject( hdc, hbm_old );
\r
2859 if( hPieceFace[index] != NULL ) {
\r
2860 DeleteObject( hPieceFace[index] );
\r
2863 hPieceFace[index] = hbm;
\r
2866 static int TranslatePieceToFontPiece( int piece )
\r
2896 case BlackMarshall:
\r
2900 case BlackNightrider:
\r
2906 case BlackUnicorn:
\r
2910 case BlackGrasshopper:
\r
2922 case BlackCardinal:
\r
2929 case WhiteMarshall:
\r
2933 case WhiteNightrider:
\r
2939 case WhiteUnicorn:
\r
2943 case WhiteGrasshopper:
\r
2955 case WhiteCardinal:
\r
2964 void CreatePiecesFromFont()
\r
2967 HDC hdc_window = NULL;
\r
2973 if( fontBitmapSquareSize < 0 ) {
\r
2974 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2978 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2979 fontBitmapSquareSize = -1;
\r
2983 if( fontBitmapSquareSize != squareSize ) {
\r
2984 hdc_window = GetDC( hwndMain );
\r
2985 hdc = CreateCompatibleDC( hdc_window );
\r
2987 if( hPieceFont != NULL ) {
\r
2988 DeleteObject( hPieceFont );
\r
2991 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2992 hPieceMask[i] = NULL;
\r
2993 hPieceFace[i] = NULL;
\r
2999 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
3000 fontHeight = appData.fontPieceSize;
\r
3003 fontHeight = (fontHeight * squareSize) / 100;
\r
3005 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
3007 lf.lfEscapement = 0;
\r
3008 lf.lfOrientation = 0;
\r
3009 lf.lfWeight = FW_NORMAL;
\r
3011 lf.lfUnderline = 0;
\r
3012 lf.lfStrikeOut = 0;
\r
3013 lf.lfCharSet = DEFAULT_CHARSET;
\r
3014 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3015 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3016 lf.lfQuality = PROOF_QUALITY;
\r
3017 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3018 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3019 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3021 hPieceFont = CreateFontIndirect( &lf );
\r
3023 if( hPieceFont == NULL ) {
\r
3024 fontBitmapSquareSize = -2;
\r
3027 /* Setup font-to-piece character table */
\r
3028 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3029 /* No (or wrong) global settings, try to detect the font */
\r
3030 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3032 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3034 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3035 /* DiagramTT* family */
\r
3036 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3038 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3039 /* Fairy symbols */
\r
3040 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3042 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3043 /* Good Companion (Some characters get warped as literal :-( */
\r
3044 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3045 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3046 SetCharTable(pieceToFontChar, s);
\r
3049 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3050 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3054 /* Create bitmaps */
\r
3055 hfont_old = SelectObject( hdc, hPieceFont );
\r
3056 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3057 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3060 SelectObject( hdc, hfont_old );
\r
3062 fontBitmapSquareSize = squareSize;
\r
3066 if( hdc != NULL ) {
\r
3070 if( hdc_window != NULL ) {
\r
3071 ReleaseDC( hwndMain, hdc_window );
\r
3076 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3080 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3081 if (gameInfo.event &&
\r
3082 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3083 strcmp(name, "k80s") == 0) {
\r
3084 strcpy(name, "tim");
\r
3086 return LoadBitmap(hinst, name);
\r
3090 /* Insert a color into the program's logical palette
\r
3091 structure. This code assumes the given color is
\r
3092 the result of the RGB or PALETTERGB macro, and it
\r
3093 knows how those macros work (which is documented).
\r
3096 InsertInPalette(COLORREF color)
\r
3098 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3100 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3101 DisplayFatalError("Too many colors", 0, 1);
\r
3102 pLogPal->palNumEntries--;
\r
3106 pe->peFlags = (char) 0;
\r
3107 pe->peRed = (char) (0xFF & color);
\r
3108 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3109 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3115 InitDrawingColors()
\r
3117 if (pLogPal == NULL) {
\r
3118 /* Allocate enough memory for a logical palette with
\r
3119 * PALETTESIZE entries and set the size and version fields
\r
3120 * of the logical palette structure.
\r
3122 pLogPal = (NPLOGPALETTE)
\r
3123 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3124 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3125 pLogPal->palVersion = 0x300;
\r
3127 pLogPal->palNumEntries = 0;
\r
3129 InsertInPalette(lightSquareColor);
\r
3130 InsertInPalette(darkSquareColor);
\r
3131 InsertInPalette(whitePieceColor);
\r
3132 InsertInPalette(blackPieceColor);
\r
3133 InsertInPalette(highlightSquareColor);
\r
3134 InsertInPalette(premoveHighlightColor);
\r
3136 /* create a logical color palette according the information
\r
3137 * in the LOGPALETTE structure.
\r
3139 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3141 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3142 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3143 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3144 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3145 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3146 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3147 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3148 /* [AS] Force rendering of the font-based pieces */
\r
3149 if( fontBitmapSquareSize > 0 ) {
\r
3150 fontBitmapSquareSize = 0;
\r
3156 BoardWidth(int boardSize, int n)
\r
3157 { /* [HGM] argument n added to allow different width and height */
\r
3158 int lineGap = sizeInfo[boardSize].lineGap;
\r
3160 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3161 lineGap = appData.overrideLineGap;
\r
3164 return (n + 1) * lineGap +
\r
3165 n * sizeInfo[boardSize].squareSize;
\r
3168 /* Respond to board resize by dragging edge */
\r
3170 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3172 BoardSize newSize = NUM_SIZES - 1;
\r
3173 static int recurse = 0;
\r
3174 if (IsIconic(hwndMain)) return;
\r
3175 if (recurse > 0) return;
\r
3177 while (newSize > 0) {
\r
3178 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3179 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3180 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3183 boardSize = newSize;
\r
3184 InitDrawingSizes(boardSize, flags);
\r
3191 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3193 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3194 ChessSquare piece;
\r
3195 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3197 SIZE clockSize, messageSize;
\r
3199 char buf[MSG_SIZ];
\r
3201 HMENU hmenu = GetMenu(hwndMain);
\r
3202 RECT crect, wrect, oldRect;
\r
3204 LOGBRUSH logbrush;
\r
3206 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3207 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3209 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3210 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3212 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3213 oldRect.top = boardY;
\r
3214 oldRect.right = boardX + winWidth;
\r
3215 oldRect.bottom = boardY + winHeight;
\r
3217 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3218 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3219 squareSize = sizeInfo[boardSize].squareSize;
\r
3220 lineGap = sizeInfo[boardSize].lineGap;
\r
3221 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3223 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3224 lineGap = appData.overrideLineGap;
\r
3227 if (tinyLayout != oldTinyLayout) {
\r
3228 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3230 style &= ~WS_SYSMENU;
\r
3231 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3232 "&Minimize\tCtrl+F4");
\r
3234 style |= WS_SYSMENU;
\r
3235 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3237 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3239 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3240 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3241 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3243 DrawMenuBar(hwndMain);
\r
3246 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3247 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3249 /* Get text area sizes */
\r
3250 hdc = GetDC(hwndMain);
\r
3251 if (appData.clockMode) {
\r
3252 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3254 sprintf(buf, "White");
\r
3256 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3257 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3258 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3259 str = "We only care about the height here";
\r
3260 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3261 SelectObject(hdc, oldFont);
\r
3262 ReleaseDC(hwndMain, hdc);
\r
3264 /* Compute where everything goes */
\r
3265 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3266 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3267 logoHeight = 2*clockSize.cy;
\r
3268 leftLogoRect.left = OUTER_MARGIN;
\r
3269 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3270 leftLogoRect.top = OUTER_MARGIN;
\r
3271 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3273 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3274 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3275 rightLogoRect.top = OUTER_MARGIN;
\r
3276 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3279 whiteRect.left = leftLogoRect.right;
\r
3280 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3281 whiteRect.top = OUTER_MARGIN;
\r
3282 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3284 blackRect.right = rightLogoRect.left;
\r
3285 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3286 blackRect.top = whiteRect.top;
\r
3287 blackRect.bottom = whiteRect.bottom;
\r
3289 whiteRect.left = OUTER_MARGIN;
\r
3290 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3291 whiteRect.top = OUTER_MARGIN;
\r
3292 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3294 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3295 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3296 blackRect.top = whiteRect.top;
\r
3297 blackRect.bottom = whiteRect.bottom;
\r
3299 logoHeight = 0; // [HGM] logo: suppress logo after change to tiny layout!
\r
3302 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3303 if (appData.showButtonBar) {
\r
3304 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3305 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3307 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3309 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3310 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3312 boardRect.left = OUTER_MARGIN;
\r
3313 boardRect.right = boardRect.left + boardWidth;
\r
3314 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3315 boardRect.bottom = boardRect.top + boardHeight;
\r
3317 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3318 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3319 oldBoardSize = boardSize;
\r
3320 oldTinyLayout = tinyLayout;
\r
3321 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3322 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3323 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3324 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3325 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3326 winHeight = winH; // without disturbing window attachments
\r
3327 GetWindowRect(hwndMain, &wrect);
\r
3328 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3329 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3331 // [HGM] placement: let attached windows follow size change.
\r
3332 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3333 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3334 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3335 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3336 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3338 /* compensate if menu bar wrapped */
\r
3339 GetClientRect(hwndMain, &crect);
\r
3340 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3341 winHeight += offby;
\r
3343 case WMSZ_TOPLEFT:
\r
3344 SetWindowPos(hwndMain, NULL,
\r
3345 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3346 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3349 case WMSZ_TOPRIGHT:
\r
3351 SetWindowPos(hwndMain, NULL,
\r
3352 wrect.left, wrect.bottom - winHeight,
\r
3353 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3356 case WMSZ_BOTTOMLEFT:
\r
3358 SetWindowPos(hwndMain, NULL,
\r
3359 wrect.right - winWidth, wrect.top,
\r
3360 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3363 case WMSZ_BOTTOMRIGHT:
\r
3367 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3368 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3373 for (i = 0; i < N_BUTTONS; i++) {
\r
3374 if (buttonDesc[i].hwnd != NULL) {
\r
3375 DestroyWindow(buttonDesc[i].hwnd);
\r
3376 buttonDesc[i].hwnd = NULL;
\r
3378 if (appData.showButtonBar) {
\r
3379 buttonDesc[i].hwnd =
\r
3380 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3381 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3382 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3383 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3384 (HMENU) buttonDesc[i].id,
\r
3385 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3387 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3388 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3389 MAKELPARAM(FALSE, 0));
\r
3391 if (buttonDesc[i].id == IDM_Pause)
\r
3392 hwndPause = buttonDesc[i].hwnd;
\r
3393 buttonDesc[i].wndproc = (WNDPROC)
\r
3394 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3397 if (gridPen != NULL) DeleteObject(gridPen);
\r
3398 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3399 if (premovePen != NULL) DeleteObject(premovePen);
\r
3400 if (lineGap != 0) {
\r
3401 logbrush.lbStyle = BS_SOLID;
\r
3402 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3404 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3405 lineGap, &logbrush, 0, NULL);
\r
3406 logbrush.lbColor = highlightSquareColor;
\r
3408 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3409 lineGap, &logbrush, 0, NULL);
\r
3411 logbrush.lbColor = premoveHighlightColor;
\r
3413 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3414 lineGap, &logbrush, 0, NULL);
\r
3416 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3417 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3418 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3419 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3420 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3421 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3422 BOARD_WIDTH * (squareSize + lineGap);
\r
3423 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3425 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3426 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3427 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3428 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3429 lineGap / 2 + (i * (squareSize + lineGap));
\r
3430 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3431 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3432 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3436 /* [HGM] Licensing requirement */
\r
3438 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3441 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3443 GothicPopUp( "", VariantNormal);
\r
3446 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3448 /* Load piece bitmaps for this board size */
\r
3449 for (i=0; i<=2; i++) {
\r
3450 for (piece = WhitePawn;
\r
3451 (int) piece < (int) BlackPawn;
\r
3452 piece = (ChessSquare) ((int) piece + 1)) {
\r
3453 if (pieceBitmap[i][piece] != NULL)
\r
3454 DeleteObject(pieceBitmap[i][piece]);
\r
3458 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3459 // Orthodox Chess pieces
\r
3460 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3461 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3462 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3463 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3464 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3465 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3466 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3467 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3468 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3469 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3470 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3471 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3472 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3473 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3474 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3475 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3476 // in Shogi, Hijack the unused Queen for Lance
\r
3477 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3478 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3479 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3481 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3482 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3483 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3486 if(squareSize <= 72 && squareSize >= 33) {
\r
3487 /* A & C are available in most sizes now */
\r
3488 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3489 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3490 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3491 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3492 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3495 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3496 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3497 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3498 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3499 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3500 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3501 } else { // Smirf-like
\r
3502 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3503 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3504 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3506 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3507 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3508 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3509 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3510 } else { // WinBoard standard
\r
3511 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3518 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3519 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3520 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3521 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3522 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3525 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3526 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3527 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3528 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3531 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3532 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3533 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3534 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3537 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3538 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3539 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3540 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3550 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3551 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3560 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3564 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3578 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3579 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3580 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3581 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3582 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3583 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3584 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3585 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3586 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3587 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3588 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3589 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3590 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3591 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3592 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3596 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3597 /* special Shogi support in this size */
\r
3598 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3599 for (piece = WhitePawn;
\r
3600 (int) piece < (int) BlackPawn;
\r
3601 piece = (ChessSquare) ((int) piece + 1)) {
\r
3602 if (pieceBitmap[i][piece] != NULL)
\r
3603 DeleteObject(pieceBitmap[i][piece]);
\r
3606 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3607 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3608 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3609 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3610 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3611 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3612 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3613 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3614 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3615 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3620 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3621 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3622 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3623 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3624 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3625 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3626 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3627 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3628 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3629 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3634 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3635 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3636 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3637 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3638 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3639 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3640 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3641 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3642 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3643 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3653 PieceBitmap(ChessSquare p, int kind)
\r
3655 if ((int) p >= (int) BlackPawn)
\r
3656 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3658 return pieceBitmap[kind][(int) p];
\r
3661 /***************************************************************/
\r
3663 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3664 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3666 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3667 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3671 SquareToPos(int row, int column, int * x, int * y)
\r
3674 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3675 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3677 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3678 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3683 DrawCoordsOnDC(HDC hdc)
\r
3685 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3686 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3687 char str[2] = { NULLCHAR, NULLCHAR };
\r
3688 int oldMode, oldAlign, x, y, start, i;
\r
3692 if (!appData.showCoords)
\r
3695 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3697 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3698 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3699 oldAlign = GetTextAlign(hdc);
\r
3700 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3702 y = boardRect.top + lineGap;
\r
3703 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3705 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3706 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3707 str[0] = files[start + i];
\r
3708 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3709 y += squareSize + lineGap;
\r
3712 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3714 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3715 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3716 str[0] = ranks[start + i];
\r
3717 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3718 x += squareSize + lineGap;
\r
3721 SelectObject(hdc, oldBrush);
\r
3722 SetBkMode(hdc, oldMode);
\r
3723 SetTextAlign(hdc, oldAlign);
\r
3724 SelectObject(hdc, oldFont);
\r
3728 DrawGridOnDC(HDC hdc)
\r
3732 if (lineGap != 0) {
\r
3733 oldPen = SelectObject(hdc, gridPen);
\r
3734 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3735 SelectObject(hdc, oldPen);
\r
3739 #define HIGHLIGHT_PEN 0
\r
3740 #define PREMOVE_PEN 1
\r
3743 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3746 HPEN oldPen, hPen;
\r
3747 if (lineGap == 0) return;
\r
3749 x1 = boardRect.left +
\r
3750 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3751 y1 = boardRect.top +
\r
3752 lineGap/2 + y * (squareSize + lineGap);
\r
3754 x1 = boardRect.left +
\r
3755 lineGap/2 + x * (squareSize + lineGap);
\r
3756 y1 = boardRect.top +
\r
3757 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3759 hPen = pen ? premovePen : highlightPen;
\r
3760 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3761 MoveToEx(hdc, x1, y1, NULL);
\r
3762 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3763 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3764 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3765 LineTo(hdc, x1, y1);
\r
3766 SelectObject(hdc, oldPen);
\r
3770 DrawHighlightsOnDC(HDC hdc)
\r
3773 for (i=0; i<2; i++) {
\r
3774 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3775 DrawHighlightOnDC(hdc, TRUE,
\r
3776 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3779 for (i=0; i<2; i++) {
\r
3780 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3781 premoveHighlightInfo.sq[i].y >= 0) {
\r
3782 DrawHighlightOnDC(hdc, TRUE,
\r
3783 premoveHighlightInfo.sq[i].x,
\r
3784 premoveHighlightInfo.sq[i].y,
\r
3790 /* Note: sqcolor is used only in monoMode */
\r
3791 /* Note that this code is largely duplicated in woptions.c,
\r
3792 function DrawSampleSquare, so that needs to be updated too */
\r
3794 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3796 HBITMAP oldBitmap;
\r
3800 if (appData.blindfold) return;
\r
3802 /* [AS] Use font-based pieces if needed */
\r
3803 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3804 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3805 CreatePiecesFromFont();
\r
3807 if( fontBitmapSquareSize == squareSize ) {
\r
3808 int index = TranslatePieceToFontPiece(piece);
\r
3810 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3814 squareSize, squareSize,
\r
3819 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3823 squareSize, squareSize,
\r
3832 if (appData.monoMode) {
\r
3833 SelectObject(tmphdc, PieceBitmap(piece,
\r
3834 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3835 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3836 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3838 tmpSize = squareSize;
\r
3840 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3841 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3842 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3843 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3844 x += (squareSize - minorSize)>>1;
\r
3845 y += squareSize - minorSize - 2;
\r
3846 tmpSize = minorSize;
\r
3848 if (color || appData.allWhite ) {
\r
3849 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3851 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3852 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3853 if(appData.upsideDown && color==flipView)
\r
3854 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3856 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3857 /* Use black for outline of white pieces */
\r
3858 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3859 if(appData.upsideDown && color==flipView)
\r
3860 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3862 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3864 /* Use square color for details of black pieces */
\r
3865 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3866 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3867 if(appData.upsideDown && !flipView)
\r
3868 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3870 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3872 SelectObject(hdc, oldBrush);
\r
3873 SelectObject(tmphdc, oldBitmap);
\r
3877 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3878 int GetBackTextureMode( int algo )
\r
3880 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3884 case BACK_TEXTURE_MODE_PLAIN:
\r
3885 result = 1; /* Always use identity map */
\r
3887 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3888 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3896 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3897 to handle redraws cleanly (as random numbers would always be different).
\r
3899 VOID RebuildTextureSquareInfo()
\r
3909 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3911 if( liteBackTexture != NULL ) {
\r
3912 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3913 lite_w = bi.bmWidth;
\r
3914 lite_h = bi.bmHeight;
\r
3918 if( darkBackTexture != NULL ) {
\r
3919 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3920 dark_w = bi.bmWidth;
\r
3921 dark_h = bi.bmHeight;
\r
3925 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3926 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3927 if( (col + row) & 1 ) {
\r
3929 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3930 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3931 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3932 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3937 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3938 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3939 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3940 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3947 /* [AS] Arrow highlighting support */
\r
3949 static int A_WIDTH = 5; /* Width of arrow body */
\r
3951 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3952 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3954 static double Sqr( double x )
\r
3959 static int Round( double x )
\r
3961 return (int) (x + 0.5);
\r
3964 /* Draw an arrow between two points using current settings */
\r
3965 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3968 double dx, dy, j, k, x, y;
\r
3970 if( d_x == s_x ) {
\r
3971 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3973 arrow[0].x = s_x + A_WIDTH;
\r
3976 arrow[1].x = s_x + A_WIDTH;
\r
3977 arrow[1].y = d_y - h;
\r
3979 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3980 arrow[2].y = d_y - h;
\r
3985 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3986 arrow[4].y = d_y - h;
\r
3988 arrow[5].x = s_x - A_WIDTH;
\r
3989 arrow[5].y = d_y - h;
\r
3991 arrow[6].x = s_x - A_WIDTH;
\r
3994 else if( d_y == s_y ) {
\r
3995 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3998 arrow[0].y = s_y + A_WIDTH;
\r
4000 arrow[1].x = d_x - w;
\r
4001 arrow[1].y = s_y + A_WIDTH;
\r
4003 arrow[2].x = d_x - w;
\r
4004 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4009 arrow[4].x = d_x - w;
\r
4010 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4012 arrow[5].x = d_x - w;
\r
4013 arrow[5].y = s_y - A_WIDTH;
\r
4016 arrow[6].y = s_y - A_WIDTH;
\r
4019 /* [AS] Needed a lot of paper for this! :-) */
\r
4020 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4021 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4023 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4025 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4030 arrow[0].x = Round(x - j);
\r
4031 arrow[0].y = Round(y + j*dx);
\r
4033 arrow[1].x = Round(x + j);
\r
4034 arrow[1].y = Round(y - j*dx);
\r
4037 x = (double) d_x - k;
\r
4038 y = (double) d_y - k*dy;
\r
4041 x = (double) d_x + k;
\r
4042 y = (double) d_y + k*dy;
\r
4045 arrow[2].x = Round(x + j);
\r
4046 arrow[2].y = Round(y - j*dx);
\r
4048 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4049 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4054 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4055 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4057 arrow[6].x = Round(x - j);
\r
4058 arrow[6].y = Round(y + j*dx);
\r
4061 Polygon( hdc, arrow, 7 );
\r
4064 /* [AS] Draw an arrow between two squares */
\r
4065 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4067 int s_x, s_y, d_x, d_y;
\r
4074 if( s_col == d_col && s_row == d_row ) {
\r
4078 /* Get source and destination points */
\r
4079 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4080 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4083 d_y += squareSize / 4;
\r
4085 else if( d_y < s_y ) {
\r
4086 d_y += 3 * squareSize / 4;
\r
4089 d_y += squareSize / 2;
\r
4093 d_x += squareSize / 4;
\r
4095 else if( d_x < s_x ) {
\r
4096 d_x += 3 * squareSize / 4;
\r
4099 d_x += squareSize / 2;
\r
4102 s_x += squareSize / 2;
\r
4103 s_y += squareSize / 2;
\r
4105 /* Adjust width */
\r
4106 A_WIDTH = squareSize / 14;
\r
4109 stLB.lbStyle = BS_SOLID;
\r
4110 stLB.lbColor = appData.highlightArrowColor;
\r
4113 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4114 holdpen = SelectObject( hdc, hpen );
\r
4115 hbrush = CreateBrushIndirect( &stLB );
\r
4116 holdbrush = SelectObject( hdc, hbrush );
\r
4118 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4120 SelectObject( hdc, holdpen );
\r
4121 SelectObject( hdc, holdbrush );
\r
4122 DeleteObject( hpen );
\r
4123 DeleteObject( hbrush );
\r
4126 BOOL HasHighlightInfo()
\r
4128 BOOL result = FALSE;
\r
4130 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4131 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4139 BOOL IsDrawArrowEnabled()
\r
4141 BOOL result = FALSE;
\r
4143 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4150 VOID DrawArrowHighlight( HDC hdc )
\r
4152 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4153 DrawArrowBetweenSquares( hdc,
\r
4154 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4155 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4159 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4161 HRGN result = NULL;
\r
4163 if( HasHighlightInfo() ) {
\r
4164 int x1, y1, x2, y2;
\r
4165 int sx, sy, dx, dy;
\r
4167 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4168 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4170 sx = MIN( x1, x2 );
\r
4171 sy = MIN( y1, y2 );
\r
4172 dx = MAX( x1, x2 ) + squareSize;
\r
4173 dy = MAX( y1, y2 ) + squareSize;
\r
4175 result = CreateRectRgn( sx, sy, dx, dy );
\r
4182 Warning: this function modifies the behavior of several other functions.
\r
4184 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4185 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4186 repaint is scattered all over the place, which is not good for features such as
\r
4187 "arrow highlighting" that require a full repaint of the board.
\r
4189 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4190 user interaction, when speed is not so important) but especially to avoid errors
\r
4191 in the displayed graphics.
\r
4193 In such patched places, I always try refer to this function so there is a single
\r
4194 place to maintain knowledge.
\r
4196 To restore the original behavior, just return FALSE unconditionally.
\r
4198 BOOL IsFullRepaintPreferrable()
\r
4200 BOOL result = FALSE;
\r
4202 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4203 /* Arrow may appear on the board */
\r
4211 This function is called by DrawPosition to know whether a full repaint must
\r
4214 Only DrawPosition may directly call this function, which makes use of
\r
4215 some state information. Other function should call DrawPosition specifying
\r
4216 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4218 BOOL DrawPositionNeedsFullRepaint()
\r
4220 BOOL result = FALSE;
\r
4223 Probably a slightly better policy would be to trigger a full repaint
\r
4224 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4225 but animation is fast enough that it's difficult to notice.
\r
4227 if( animInfo.piece == EmptySquare ) {
\r
4228 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4237 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4239 int row, column, x, y, square_color, piece_color;
\r
4240 ChessSquare piece;
\r
4242 HDC texture_hdc = NULL;
\r
4244 /* [AS] Initialize background textures if needed */
\r
4245 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4246 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4247 if( backTextureSquareSize != squareSize
\r
4248 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4249 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4250 backTextureSquareSize = squareSize;
\r
4251 RebuildTextureSquareInfo();
\r
4254 texture_hdc = CreateCompatibleDC( hdc );
\r
4257 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4258 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4260 SquareToPos(row, column, &x, &y);
\r
4262 piece = board[row][column];
\r
4264 square_color = ((column + row) % 2) == 1;
\r
4265 if( gameInfo.variant == VariantXiangqi ) {
\r
4266 square_color = !InPalace(row, column);
\r
4267 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4268 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4270 piece_color = (int) piece < (int) BlackPawn;
\r
4273 /* [HGM] holdings file: light square or black */
\r
4274 if(column == BOARD_LEFT-2) {
\r
4275 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4278 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4282 if(column == BOARD_RGHT + 1 ) {
\r
4283 if( row < gameInfo.holdingsSize )
\r
4286 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4290 if(column == BOARD_LEFT-1 ) /* left align */
\r
4291 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4292 else if( column == BOARD_RGHT) /* right align */
\r
4293 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4295 if (appData.monoMode) {
\r
4296 if (piece == EmptySquare) {
\r
4297 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4298 square_color ? WHITENESS : BLACKNESS);
\r
4300 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4303 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4304 /* [AS] Draw the square using a texture bitmap */
\r
4305 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4306 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4307 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4310 squareSize, squareSize,
\r
4313 backTextureSquareInfo[r][c].mode,
\r
4314 backTextureSquareInfo[r][c].x,
\r
4315 backTextureSquareInfo[r][c].y );
\r
4317 SelectObject( texture_hdc, hbm );
\r
4319 if (piece != EmptySquare) {
\r
4320 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4324 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4326 oldBrush = SelectObject(hdc, brush );
\r
4327 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4328 SelectObject(hdc, oldBrush);
\r
4329 if (piece != EmptySquare)
\r
4330 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4335 if( texture_hdc != NULL ) {
\r
4336 DeleteDC( texture_hdc );
\r
4340 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4341 void fputDW(FILE *f, int x)
\r
4343 fputc(x & 255, f);
\r
4344 fputc(x>>8 & 255, f);
\r
4345 fputc(x>>16 & 255, f);
\r
4346 fputc(x>>24 & 255, f);
\r
4349 #define MAX_CLIPS 200 /* more than enough */
\r
4352 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4354 // HBITMAP bufferBitmap;
\r
4359 int w = 100, h = 50;
\r
4361 if(logo == NULL) return;
\r
4362 // GetClientRect(hwndMain, &Rect);
\r
4363 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4364 // Rect.bottom-Rect.top+1);
\r
4365 tmphdc = CreateCompatibleDC(hdc);
\r
4366 hbm = SelectObject(tmphdc, logo);
\r
4367 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4371 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4372 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4373 SelectObject(tmphdc, hbm);
\r
4378 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4380 static Board lastReq, lastDrawn;
\r
4381 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4382 static int lastDrawnFlipView = 0;
\r
4383 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4384 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4387 HBITMAP bufferBitmap;
\r
4388 HBITMAP oldBitmap;
\r
4390 HRGN clips[MAX_CLIPS];
\r
4391 ChessSquare dragged_piece = EmptySquare;
\r
4393 /* I'm undecided on this - this function figures out whether a full
\r
4394 * repaint is necessary on its own, so there's no real reason to have the
\r
4395 * caller tell it that. I think this can safely be set to FALSE - but
\r
4396 * if we trust the callers not to request full repaints unnessesarily, then
\r
4397 * we could skip some clipping work. In other words, only request a full
\r
4398 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4399 * gamestart and similar) --Hawk
\r
4401 Boolean fullrepaint = repaint;
\r
4403 if( DrawPositionNeedsFullRepaint() ) {
\r
4404 fullrepaint = TRUE;
\r
4407 if (board == NULL) {
\r
4408 if (!lastReqValid) {
\r
4413 CopyBoard(lastReq, board);
\r
4417 if (doingSizing) {
\r
4421 if (IsIconic(hwndMain)) {
\r
4425 if (hdc == NULL) {
\r
4426 hdc = GetDC(hwndMain);
\r
4427 if (!appData.monoMode) {
\r
4428 SelectPalette(hdc, hPal, FALSE);
\r
4429 RealizePalette(hdc);
\r
4433 releaseDC = FALSE;
\r
4436 /* Create some work-DCs */
\r
4437 hdcmem = CreateCompatibleDC(hdc);
\r
4438 tmphdc = CreateCompatibleDC(hdc);
\r
4440 /* If dragging is in progress, we temporarely remove the piece */
\r
4441 /* [HGM] or temporarily decrease count if stacked */
\r
4442 /* !! Moved to before board compare !! */
\r
4443 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4444 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4445 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4446 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4447 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4449 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4450 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4451 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4453 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4456 /* Figure out which squares need updating by comparing the
\r
4457 * newest board with the last drawn board and checking if
\r
4458 * flipping has changed.
\r
4460 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4461 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4462 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4463 if (lastDrawn[row][column] != board[row][column]) {
\r
4464 SquareToPos(row, column, &x, &y);
\r
4465 clips[num_clips++] =
\r
4466 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4470 for (i=0; i<2; i++) {
\r
4471 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4472 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4473 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4474 lastDrawnHighlight.sq[i].y >= 0) {
\r
4475 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4476 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4477 clips[num_clips++] =
\r
4478 CreateRectRgn(x - lineGap, y - lineGap,
\r
4479 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4481 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4482 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4483 clips[num_clips++] =
\r
4484 CreateRectRgn(x - lineGap, y - lineGap,
\r
4485 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4489 for (i=0; i<2; i++) {
\r
4490 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4491 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4492 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4493 lastDrawnPremove.sq[i].y >= 0) {
\r
4494 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4495 lastDrawnPremove.sq[i].x, &x, &y);
\r
4496 clips[num_clips++] =
\r
4497 CreateRectRgn(x - lineGap, y - lineGap,
\r
4498 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4500 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4501 premoveHighlightInfo.sq[i].y >= 0) {
\r
4502 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4503 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4504 clips[num_clips++] =
\r
4505 CreateRectRgn(x - lineGap, y - lineGap,
\r
4506 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4511 fullrepaint = TRUE;
\r
4514 /* Create a buffer bitmap - this is the actual bitmap
\r
4515 * being written to. When all the work is done, we can
\r
4516 * copy it to the real DC (the screen). This avoids
\r
4517 * the problems with flickering.
\r
4519 GetClientRect(hwndMain, &Rect);
\r
4520 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4521 Rect.bottom-Rect.top+1);
\r
4522 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4523 if (!appData.monoMode) {
\r
4524 SelectPalette(hdcmem, hPal, FALSE);
\r
4527 /* Create clips for dragging */
\r
4528 if (!fullrepaint) {
\r
4529 if (dragInfo.from.x >= 0) {
\r
4530 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4531 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4533 if (dragInfo.start.x >= 0) {
\r
4534 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4535 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4537 if (dragInfo.pos.x >= 0) {
\r
4538 x = dragInfo.pos.x - squareSize / 2;
\r
4539 y = dragInfo.pos.y - squareSize / 2;
\r
4540 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4542 if (dragInfo.lastpos.x >= 0) {
\r
4543 x = dragInfo.lastpos.x - squareSize / 2;
\r
4544 y = dragInfo.lastpos.y - squareSize / 2;
\r
4545 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4549 /* Are we animating a move?
\r
4551 * - remove the piece from the board (temporarely)
\r
4552 * - calculate the clipping region
\r
4554 if (!fullrepaint) {
\r
4555 if (animInfo.piece != EmptySquare) {
\r
4556 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4557 x = boardRect.left + animInfo.lastpos.x;
\r
4558 y = boardRect.top + animInfo.lastpos.y;
\r
4559 x2 = boardRect.left + animInfo.pos.x;
\r
4560 y2 = boardRect.top + animInfo.pos.y;
\r
4561 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4562 /* Slight kludge. The real problem is that after AnimateMove is
\r
4563 done, the position on the screen does not match lastDrawn.
\r
4564 This currently causes trouble only on e.p. captures in
\r
4565 atomic, where the piece moves to an empty square and then
\r
4566 explodes. The old and new positions both had an empty square
\r
4567 at the destination, but animation has drawn a piece there and
\r
4568 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4569 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4573 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4574 if (num_clips == 0)
\r
4575 fullrepaint = TRUE;
\r
4577 /* Set clipping on the memory DC */
\r
4578 if (!fullrepaint) {
\r
4579 SelectClipRgn(hdcmem, clips[0]);
\r
4580 for (x = 1; x < num_clips; x++) {
\r
4581 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4582 abort(); // this should never ever happen!
\r
4586 /* Do all the drawing to the memory DC */
\r
4587 if(explodeInfo.radius) { // [HGM] atomic
\r
4589 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4590 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4591 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4592 x += squareSize/2;
\r
4593 y += squareSize/2;
\r
4594 if(!fullrepaint) {
\r
4595 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4596 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4598 DrawGridOnDC(hdcmem);
\r
4599 DrawHighlightsOnDC(hdcmem);
\r
4600 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4601 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4602 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4603 SelectObject(hdcmem, oldBrush);
\r
4605 DrawGridOnDC(hdcmem);
\r
4606 DrawHighlightsOnDC(hdcmem);
\r
4607 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4610 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4611 if(appData.autoLogo) {
\r
4613 switch(gameMode) { // pick logos based on game mode
\r
4614 case IcsObserving:
\r
4615 whiteLogo = second.programLogo; // ICS logo
\r
4616 blackLogo = second.programLogo;
\r
4619 case IcsPlayingWhite:
\r
4620 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4621 blackLogo = second.programLogo; // ICS logo
\r
4623 case IcsPlayingBlack:
\r
4624 whiteLogo = second.programLogo; // ICS logo
\r
4625 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4627 case TwoMachinesPlay:
\r
4628 if(first.twoMachinesColor[0] == 'b') {
\r
4629 whiteLogo = second.programLogo;
\r
4630 blackLogo = first.programLogo;
\r
4633 case MachinePlaysWhite:
\r
4634 blackLogo = userLogo;
\r
4636 case MachinePlaysBlack:
\r
4637 whiteLogo = userLogo;
\r
4638 blackLogo = first.programLogo;
\r
4641 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4642 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4645 if( appData.highlightMoveWithArrow ) {
\r
4646 DrawArrowHighlight(hdcmem);
\r
4649 DrawCoordsOnDC(hdcmem);
\r
4651 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4652 /* to make sure lastDrawn contains what is actually drawn */
\r
4654 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4655 if (dragged_piece != EmptySquare) {
\r
4656 /* [HGM] or restack */
\r
4657 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4658 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4660 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4661 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4662 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4663 x = dragInfo.pos.x - squareSize / 2;
\r
4664 y = dragInfo.pos.y - squareSize / 2;
\r
4665 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4666 ((int) dragged_piece < (int) BlackPawn),
\r
4667 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4670 /* Put the animated piece back into place and draw it */
\r
4671 if (animInfo.piece != EmptySquare) {
\r
4672 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4673 x = boardRect.left + animInfo.pos.x;
\r
4674 y = boardRect.top + animInfo.pos.y;
\r
4675 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4676 ((int) animInfo.piece < (int) BlackPawn),
\r
4677 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4680 /* Release the bufferBitmap by selecting in the old bitmap
\r
4681 * and delete the memory DC
\r
4683 SelectObject(hdcmem, oldBitmap);
\r
4686 /* Set clipping on the target DC */
\r
4687 if (!fullrepaint) {
\r
4688 SelectClipRgn(hdc, clips[0]);
\r
4689 for (x = 1; x < num_clips; x++) {
\r
4690 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4691 abort(); // this should never ever happen!
\r
4695 /* Copy the new bitmap onto the screen in one go.
\r
4696 * This way we avoid any flickering
\r
4698 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4699 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4700 boardRect.right - boardRect.left,
\r
4701 boardRect.bottom - boardRect.top,
\r
4702 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4703 if(saveDiagFlag) {
\r
4704 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4705 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4707 GetObject(bufferBitmap, sizeof(b), &b);
\r
4708 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4709 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4710 bih.biWidth = b.bmWidth;
\r
4711 bih.biHeight = b.bmHeight;
\r
4713 bih.biBitCount = b.bmBitsPixel;
\r
4714 bih.biCompression = 0;
\r
4715 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4716 bih.biXPelsPerMeter = 0;
\r
4717 bih.biYPelsPerMeter = 0;
\r
4718 bih.biClrUsed = 0;
\r
4719 bih.biClrImportant = 0;
\r
4720 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4721 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4722 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4723 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4725 wb = b.bmWidthBytes;
\r
4727 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4728 int k = ((int*) pData)[i];
\r
4729 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4730 if(j >= 16) break;
\r
4732 if(j >= nrColors) nrColors = j+1;
\r
4734 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4736 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4737 for(w=0; w<(wb>>2); w+=2) {
\r
4738 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4739 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4740 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4741 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4742 pData[p++] = m | j<<4;
\r
4744 while(p&3) pData[p++] = 0;
\r
4747 wb = ((wb+31)>>5)<<2;
\r
4749 // write BITMAPFILEHEADER
\r
4750 fprintf(diagFile, "BM");
\r
4751 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4752 fputDW(diagFile, 0);
\r
4753 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4754 // write BITMAPINFOHEADER
\r
4755 fputDW(diagFile, 40);
\r
4756 fputDW(diagFile, b.bmWidth);
\r
4757 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4758 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4759 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4760 fputDW(diagFile, 0);
\r
4761 fputDW(diagFile, 0);
\r
4762 fputDW(diagFile, 0);
\r
4763 fputDW(diagFile, 0);
\r
4764 fputDW(diagFile, 0);
\r
4765 fputDW(diagFile, 0);
\r
4766 // write color table
\r
4768 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4769 // write bitmap data
\r
4770 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4771 fputc(pData[i], diagFile);
\r
4775 SelectObject(tmphdc, oldBitmap);
\r
4777 /* Massive cleanup */
\r
4778 for (x = 0; x < num_clips; x++)
\r
4779 DeleteObject(clips[x]);
\r
4782 DeleteObject(bufferBitmap);
\r
4785 ReleaseDC(hwndMain, hdc);
\r
4787 if (lastDrawnFlipView != flipView) {
\r
4789 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4791 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4794 /* CopyBoard(lastDrawn, board);*/
\r
4795 lastDrawnHighlight = highlightInfo;
\r
4796 lastDrawnPremove = premoveHighlightInfo;
\r
4797 lastDrawnFlipView = flipView;
\r
4798 lastDrawnValid = 1;
\r
4801 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4806 saveDiagFlag = 1; diagFile = f;
\r
4807 HDCDrawPosition(NULL, TRUE, NULL);
\r
4811 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4818 /*---------------------------------------------------------------------------*\
\r
4819 | CLIENT PAINT PROCEDURE
\r
4820 | This is the main event-handler for the WM_PAINT message.
\r
4822 \*---------------------------------------------------------------------------*/
\r
4824 PaintProc(HWND hwnd)
\r
4830 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4831 if (IsIconic(hwnd)) {
\r
4832 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4834 if (!appData.monoMode) {
\r
4835 SelectPalette(hdc, hPal, FALSE);
\r
4836 RealizePalette(hdc);
\r
4838 HDCDrawPosition(hdc, 1, NULL);
\r
4840 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4841 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4842 ETO_CLIPPED|ETO_OPAQUE,
\r
4843 &messageRect, messageText, strlen(messageText), NULL);
\r
4844 SelectObject(hdc, oldFont);
\r
4845 DisplayBothClocks();
\r
4847 EndPaint(hwnd,&ps);
\r
4855 * If the user selects on a border boundary, return -1; if off the board,
\r
4856 * return -2. Otherwise map the event coordinate to the square.
\r
4857 * The offset boardRect.left or boardRect.top must already have been
\r
4858 * subtracted from x.
\r
4860 int EventToSquare(x, limit)
\r
4868 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4870 x /= (squareSize + lineGap);
\r
4882 DropEnable dropEnables[] = {
\r
4883 { 'P', DP_Pawn, "Pawn" },
\r
4884 { 'N', DP_Knight, "Knight" },
\r
4885 { 'B', DP_Bishop, "Bishop" },
\r
4886 { 'R', DP_Rook, "Rook" },
\r
4887 { 'Q', DP_Queen, "Queen" },
\r
4891 SetupDropMenu(HMENU hmenu)
\r
4893 int i, count, enable;
\r
4895 extern char white_holding[], black_holding[];
\r
4896 char item[MSG_SIZ];
\r
4898 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4899 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4900 dropEnables[i].piece);
\r
4902 while (p && *p++ == dropEnables[i].piece) count++;
\r
4903 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4904 enable = count > 0 || !appData.testLegality
\r
4905 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4906 && !appData.icsActive);
\r
4907 ModifyMenu(hmenu, dropEnables[i].command,
\r
4908 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4909 dropEnables[i].command, item);
\r
4913 void DragPieceBegin(int x, int y)
\r
4915 dragInfo.lastpos.x = boardRect.left + x;
\r
4916 dragInfo.lastpos.y = boardRect.top + y;
\r
4917 dragInfo.from.x = fromX;
\r
4918 dragInfo.from.y = fromY;
\r
4919 dragInfo.start = dragInfo.from;
\r
4920 SetCapture(hwndMain);
\r
4923 void DragPieceEnd(int x, int y)
\r
4926 dragInfo.start.x = dragInfo.start.y = -1;
\r
4927 dragInfo.from = dragInfo.start;
\r
4928 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4931 /* Event handler for mouse messages */
\r
4933 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4937 static int recursive = 0;
\r
4939 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4942 if (message == WM_MBUTTONUP) {
\r
4943 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4944 to the middle button: we simulate pressing the left button too!
\r
4946 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4947 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4953 pt.x = LOWORD(lParam);
\r
4954 pt.y = HIWORD(lParam);
\r
4955 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4956 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4957 if (!flipView && y >= 0) {
\r
4958 y = BOARD_HEIGHT - 1 - y;
\r
4960 if (flipView && x >= 0) {
\r
4961 x = BOARD_WIDTH - 1 - x;
\r
4964 switch (message) {
\r
4965 case WM_LBUTTONDOWN:
\r
4966 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4967 if (gameMode == EditPosition) {
\r
4968 SetWhiteToPlayEvent();
\r
4969 } else if (gameMode == IcsPlayingBlack ||
\r
4970 gameMode == MachinePlaysWhite) {
\r
4972 } else if (gameMode == EditGame) {
\r
4973 AdjustClock(flipClock, -1);
\r
4975 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4976 if (gameMode == EditPosition) {
\r
4977 SetBlackToPlayEvent();
\r
4978 } else if (gameMode == IcsPlayingWhite ||
\r
4979 gameMode == MachinePlaysBlack) {
\r
4981 } else if (gameMode == EditGame) {
\r
4982 AdjustClock(!flipClock, -1);
\r
4985 dragInfo.start.x = dragInfo.start.y = -1;
\r
4986 dragInfo.from = dragInfo.start;
\r
4987 if(fromX == -1 && frozen) { // not sure where this is for
\r
4988 fromX = fromY = -1;
\r
4989 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4992 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4993 DrawPosition(TRUE, NULL);
\r
4996 case WM_LBUTTONUP:
\r
4997 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4998 DrawPosition(TRUE, NULL);
\r
5001 case WM_MOUSEMOVE:
\r
5002 if ((appData.animateDragging || appData.highlightDragging)
\r
5003 && (wParam & MK_LBUTTON)
\r
5004 && dragInfo.from.x >= 0)
\r
5006 BOOL full_repaint = FALSE;
\r
5008 if (appData.animateDragging) {
\r
5009 dragInfo.pos = pt;
\r
5011 if (appData.highlightDragging) {
\r
5012 SetHighlights(fromX, fromY, x, y);
\r
5013 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5014 full_repaint = TRUE;
\r
5018 DrawPosition( full_repaint, NULL);
\r
5020 dragInfo.lastpos = dragInfo.pos;
\r
5024 case WM_MOUSEWHEEL: // [DM]
\r
5025 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5026 /* Mouse Wheel is being rolled forward
\r
5027 * Play moves forward
\r
5029 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5030 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5031 /* Mouse Wheel is being rolled backward
\r
5032 * Play moves backward
\r
5034 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5035 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5039 case WM_MBUTTONDOWN:
\r
5040 case WM_RBUTTONDOWN:
\r
5043 fromX = fromY = -1;
\r
5044 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5045 dragInfo.start.x = dragInfo.start.y = -1;
\r
5046 dragInfo.from = dragInfo.start;
\r
5047 dragInfo.lastpos = dragInfo.pos;
\r
5048 if (appData.highlightDragging) {
\r
5049 ClearHighlights();
\r
5052 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5053 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5054 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5055 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5056 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5059 DrawPosition(TRUE, NULL);
\r
5061 switch (gameMode) {
\r
5062 case EditPosition:
\r
5063 case IcsExamining:
\r
5064 if (x < 0 || y < 0) break;
\r
5067 if (message == WM_MBUTTONDOWN) {
\r
5068 buttonCount = 3; /* even if system didn't think so */
\r
5069 if (wParam & MK_SHIFT)
\r
5070 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5072 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5073 } else { /* message == WM_RBUTTONDOWN */
\r
5074 /* Just have one menu, on the right button. Windows users don't
\r
5075 think to try the middle one, and sometimes other software steals
\r
5076 it, or it doesn't really exist. */
\r
5077 if(gameInfo.variant != VariantShogi)
\r
5078 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5080 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5083 case IcsPlayingWhite:
\r
5084 case IcsPlayingBlack:
\r
5086 case MachinePlaysWhite:
\r
5087 case MachinePlaysBlack:
\r
5088 if (appData.testLegality &&
\r
5089 gameInfo.variant != VariantBughouse &&
\r
5090 gameInfo.variant != VariantCrazyhouse) break;
\r
5091 if (x < 0 || y < 0) break;
\r
5094 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5095 SetupDropMenu(hmenu);
\r
5096 MenuPopup(hwnd, pt, hmenu, -1);
\r
5107 /* Preprocess messages for buttons in main window */
\r
5109 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5111 int id = GetWindowLong(hwnd, GWL_ID);
\r
5114 for (i=0; i<N_BUTTONS; i++) {
\r
5115 if (buttonDesc[i].id == id) break;
\r
5117 if (i == N_BUTTONS) return 0;
\r
5118 switch (message) {
\r
5123 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5124 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5131 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5134 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5135 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5136 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5137 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5139 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5141 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5142 PopUpMoveDialog((char)wParam);
\r
5148 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5151 /* Process messages for Promotion dialog box */
\r
5153 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5157 switch (message) {
\r
5158 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5159 /* Center the dialog over the application window */
\r
5160 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5161 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5162 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5163 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5164 SW_SHOW : SW_HIDE);
\r
5165 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5166 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5167 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5168 PieceToChar(WhiteAngel) != '~') ||
\r
5169 (PieceToChar(BlackAngel) >= 'A' &&
\r
5170 PieceToChar(BlackAngel) != '~') ) ?
\r
5171 SW_SHOW : SW_HIDE);
\r
5172 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5173 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5174 PieceToChar(WhiteMarshall) != '~') ||
\r
5175 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5176 PieceToChar(BlackMarshall) != '~') ) ?
\r
5177 SW_SHOW : SW_HIDE);
\r
5178 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5179 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5180 gameInfo.variant != VariantShogi ?
\r
5181 SW_SHOW : SW_HIDE);
\r
5182 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5183 gameInfo.variant != VariantShogi ?
\r
5184 SW_SHOW : SW_HIDE);
\r
5185 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5186 gameInfo.variant == VariantShogi ?
\r
5187 SW_SHOW : SW_HIDE);
\r
5188 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5189 gameInfo.variant == VariantShogi ?
\r
5190 SW_SHOW : SW_HIDE);
\r
5191 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5192 gameInfo.variant == VariantSuper ?
\r
5193 SW_SHOW : SW_HIDE);
\r
5196 case WM_COMMAND: /* message: received a command */
\r
5197 switch (LOWORD(wParam)) {
\r
5199 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5200 ClearHighlights();
\r
5201 DrawPosition(FALSE, NULL);
\r
5204 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5207 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5210 promoChar = PieceToChar(BlackRook);
\r
5213 promoChar = PieceToChar(BlackBishop);
\r
5215 case PB_Chancellor:
\r
5216 promoChar = PieceToChar(BlackMarshall);
\r
5218 case PB_Archbishop:
\r
5219 promoChar = PieceToChar(BlackAngel);
\r
5222 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5227 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5228 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5229 only show the popup when we are already sure the move is valid or
\r
5230 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5231 will figure out it is a promotion from the promoChar. */
\r
5232 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5233 fromX = fromY = -1;
\r
5234 if (!appData.highlightLastMove) {
\r
5235 ClearHighlights();
\r
5236 DrawPosition(FALSE, NULL);
\r
5243 /* Pop up promotion dialog */
\r
5245 PromotionPopup(HWND hwnd)
\r
5249 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5250 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5251 hwnd, (DLGPROC)lpProc);
\r
5252 FreeProcInstance(lpProc);
\r
5258 DrawPosition(TRUE, NULL);
\r
5259 PromotionPopup(hwndMain);
\r
5262 /* Toggle ShowThinking */
\r
5264 ToggleShowThinking()
\r
5266 appData.showThinking = !appData.showThinking;
\r
5267 ShowThinkingEvent();
\r
5271 LoadGameDialog(HWND hwnd, char* title)
\r
5275 char fileTitle[MSG_SIZ];
\r
5276 f = OpenFileDialog(hwnd, "rb", "",
\r
5277 appData.oldSaveStyle ? "gam" : "pgn",
\r
5279 title, &number, fileTitle, NULL);
\r
5281 cmailMsgLoaded = FALSE;
\r
5282 if (number == 0) {
\r
5283 int error = GameListBuild(f);
\r
5285 DisplayError("Cannot build game list", error);
\r
5286 } else if (!ListEmpty(&gameList) &&
\r
5287 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5288 GameListPopUp(f, fileTitle);
\r
5291 GameListDestroy();
\r
5294 LoadGame(f, number, fileTitle, FALSE);
\r
5298 int get_term_width()
\r
5303 HFONT hfont, hold_font;
\r
5308 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5312 // get the text metrics
\r
5313 hdc = GetDC(hText);
\r
5314 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5315 if (consoleCF.dwEffects & CFE_BOLD)
\r
5316 lf.lfWeight = FW_BOLD;
\r
5317 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5318 lf.lfItalic = TRUE;
\r
5319 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5320 lf.lfStrikeOut = TRUE;
\r
5321 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5322 lf.lfUnderline = TRUE;
\r
5323 hfont = CreateFontIndirect(&lf);
\r
5324 hold_font = SelectObject(hdc, hfont);
\r
5325 GetTextMetrics(hdc, &tm);
\r
5326 SelectObject(hdc, hold_font);
\r
5327 DeleteObject(hfont);
\r
5328 ReleaseDC(hText, hdc);
\r
5330 // get the rectangle
\r
5331 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5333 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5336 void UpdateICSWidth(HWND hText)
\r
5338 LONG old_width, new_width;
\r
5340 new_width = get_term_width(hText, FALSE);
\r
5341 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5342 if (new_width != old_width)
\r
5344 ics_update_width(new_width);
\r
5345 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5350 ChangedConsoleFont()
\r
5353 CHARRANGE tmpsel, sel;
\r
5354 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5355 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5356 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5359 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5360 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5361 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5362 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5363 * size. This was undocumented in the version of MSVC++ that I had
\r
5364 * when I wrote the code, but is apparently documented now.
\r
5366 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5367 cfmt.bCharSet = f->lf.lfCharSet;
\r
5368 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5369 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5370 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5371 /* Why are the following seemingly needed too? */
\r
5372 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5373 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5374 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5376 tmpsel.cpMax = -1; /*999999?*/
\r
5377 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5378 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5379 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5380 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5382 paraf.cbSize = sizeof(paraf);
\r
5383 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5384 paraf.dxStartIndent = 0;
\r
5385 paraf.dxOffset = WRAP_INDENT;
\r
5386 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5387 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5388 UpdateICSWidth(hText);
\r
5391 /*---------------------------------------------------------------------------*\
\r
5393 * Window Proc for main window
\r
5395 \*---------------------------------------------------------------------------*/
\r
5397 /* Process messages for main window, etc. */
\r
5399 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5402 int wmId, wmEvent;
\r
5406 char fileTitle[MSG_SIZ];
\r
5407 char buf[MSG_SIZ];
\r
5408 static SnapData sd;
\r
5410 switch (message) {
\r
5412 case WM_PAINT: /* message: repaint portion of window */
\r
5416 case WM_ERASEBKGND:
\r
5417 if (IsIconic(hwnd)) {
\r
5418 /* Cheat; change the message */
\r
5419 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5421 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5425 case WM_LBUTTONDOWN:
\r
5426 case WM_MBUTTONDOWN:
\r
5427 case WM_RBUTTONDOWN:
\r
5428 case WM_LBUTTONUP:
\r
5429 case WM_MBUTTONUP:
\r
5430 case WM_RBUTTONUP:
\r
5431 case WM_MOUSEMOVE:
\r
5432 case WM_MOUSEWHEEL:
\r
5433 MouseEvent(hwnd, message, wParam, lParam);
\r
5436 JAWS_KB_NAVIGATION
\r
5440 JAWS_ALT_INTERCEPT
\r
5442 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5443 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5444 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5445 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5447 SendMessage(h, message, wParam, lParam);
\r
5448 } else if(lParam != KF_REPEAT) {
\r
5449 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5450 PopUpMoveDialog((char)wParam);
\r
5451 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5452 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5457 case WM_PALETTECHANGED:
\r
5458 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5460 HDC hdc = GetDC(hwndMain);
\r
5461 SelectPalette(hdc, hPal, TRUE);
\r
5462 nnew = RealizePalette(hdc);
\r
5464 paletteChanged = TRUE;
\r
5465 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5467 ReleaseDC(hwnd, hdc);
\r
5471 case WM_QUERYNEWPALETTE:
\r
5472 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5474 HDC hdc = GetDC(hwndMain);
\r
5475 paletteChanged = FALSE;
\r
5476 SelectPalette(hdc, hPal, FALSE);
\r
5477 nnew = RealizePalette(hdc);
\r
5479 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5481 ReleaseDC(hwnd, hdc);
\r
5486 case WM_COMMAND: /* message: command from application menu */
\r
5487 wmId = LOWORD(wParam);
\r
5488 wmEvent = HIWORD(wParam);
\r
5493 SAY("new game enter a move to play against the computer with white");
\r
5496 case IDM_NewGameFRC:
\r
5497 if( NewGameFRC() == 0 ) {
\r
5502 case IDM_NewVariant:
\r
5503 NewVariantPopup(hwnd);
\r
5506 case IDM_LoadGame:
\r
5507 LoadGameDialog(hwnd, "Load Game from File");
\r
5510 case IDM_LoadNextGame:
\r
5514 case IDM_LoadPrevGame:
\r
5518 case IDM_ReloadGame:
\r
5522 case IDM_LoadPosition:
\r
5523 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5524 Reset(FALSE, TRUE);
\r
5527 f = OpenFileDialog(hwnd, "rb", "",
\r
5528 appData.oldSaveStyle ? "pos" : "fen",
\r
5530 "Load Position from File", &number, fileTitle, NULL);
\r
5532 LoadPosition(f, number, fileTitle);
\r
5536 case IDM_LoadNextPosition:
\r
5537 ReloadPosition(1);
\r
5540 case IDM_LoadPrevPosition:
\r
5541 ReloadPosition(-1);
\r
5544 case IDM_ReloadPosition:
\r
5545 ReloadPosition(0);
\r
5548 case IDM_SaveGame:
\r
5549 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5550 f = OpenFileDialog(hwnd, "a", defName,
\r
5551 appData.oldSaveStyle ? "gam" : "pgn",
\r
5553 "Save Game to File", NULL, fileTitle, NULL);
\r
5555 SaveGame(f, 0, "");
\r
5559 case IDM_SavePosition:
\r
5560 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5561 f = OpenFileDialog(hwnd, "a", defName,
\r
5562 appData.oldSaveStyle ? "pos" : "fen",
\r
5564 "Save Position to File", NULL, fileTitle, NULL);
\r
5566 SavePosition(f, 0, "");
\r
5570 case IDM_SaveDiagram:
\r
5571 defName = "diagram";
\r
5572 f = OpenFileDialog(hwnd, "wb", defName,
\r
5575 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5581 case IDM_CopyGame:
\r
5582 CopyGameToClipboard();
\r
5585 case IDM_PasteGame:
\r
5586 PasteGameFromClipboard();
\r
5589 case IDM_CopyGameListToClipboard:
\r
5590 CopyGameListToClipboard();
\r
5593 /* [AS] Autodetect FEN or PGN data */
\r
5594 case IDM_PasteAny:
\r
5595 PasteGameOrFENFromClipboard();
\r
5598 /* [AS] Move history */
\r
5599 case IDM_ShowMoveHistory:
\r
5600 if( MoveHistoryIsUp() ) {
\r
5601 MoveHistoryPopDown();
\r
5604 MoveHistoryPopUp();
\r
5608 /* [AS] Eval graph */
\r
5609 case IDM_ShowEvalGraph:
\r
5610 if( EvalGraphIsUp() ) {
\r
5611 EvalGraphPopDown();
\r
5615 SetFocus(hwndMain);
\r
5619 /* [AS] Engine output */
\r
5620 case IDM_ShowEngineOutput:
\r
5621 if( EngineOutputIsUp() ) {
\r
5622 EngineOutputPopDown();
\r
5625 EngineOutputPopUp();
\r
5629 /* [AS] User adjudication */
\r
5630 case IDM_UserAdjudication_White:
\r
5631 UserAdjudicationEvent( +1 );
\r
5634 case IDM_UserAdjudication_Black:
\r
5635 UserAdjudicationEvent( -1 );
\r
5638 case IDM_UserAdjudication_Draw:
\r
5639 UserAdjudicationEvent( 0 );
\r
5642 /* [AS] Game list options dialog */
\r
5643 case IDM_GameListOptions:
\r
5644 GameListOptions();
\r
5651 case IDM_CopyPosition:
\r
5652 CopyFENToClipboard();
\r
5655 case IDM_PastePosition:
\r
5656 PasteFENFromClipboard();
\r
5659 case IDM_MailMove:
\r
5663 case IDM_ReloadCMailMsg:
\r
5664 Reset(TRUE, TRUE);
\r
5665 ReloadCmailMsgEvent(FALSE);
\r
5668 case IDM_Minimize:
\r
5669 ShowWindow(hwnd, SW_MINIMIZE);
\r
5676 case IDM_MachineWhite:
\r
5677 MachineWhiteEvent();
\r
5679 * refresh the tags dialog only if it's visible
\r
5681 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5683 tags = PGNTags(&gameInfo);
\r
5684 TagsPopUp(tags, CmailMsg());
\r
5687 SAY("computer starts playing white");
\r
5690 case IDM_MachineBlack:
\r
5691 MachineBlackEvent();
\r
5693 * refresh the tags dialog only if it's visible
\r
5695 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5697 tags = PGNTags(&gameInfo);
\r
5698 TagsPopUp(tags, CmailMsg());
\r
5701 SAY("computer starts playing black");
\r
5704 case IDM_TwoMachines:
\r
5705 TwoMachinesEvent();
\r
5707 * refresh the tags dialog only if it's visible
\r
5709 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5711 tags = PGNTags(&gameInfo);
\r
5712 TagsPopUp(tags, CmailMsg());
\r
5715 SAY("programs start playing each other");
\r
5718 case IDM_AnalysisMode:
\r
5719 if (!first.analysisSupport) {
\r
5720 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5721 DisplayError(buf, 0);
\r
5723 SAY("analyzing current position");
\r
5724 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5725 if (appData.icsActive) {
\r
5726 if (gameMode != IcsObserving) {
\r
5727 sprintf(buf, "You are not observing a game");
\r
5728 DisplayError(buf, 0);
\r
5729 /* secure check */
\r
5730 if (appData.icsEngineAnalyze) {
\r
5731 if (appData.debugMode)
\r
5732 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5733 ExitAnalyzeMode();
\r
5739 /* if enable, user want disable icsEngineAnalyze */
\r
5740 if (appData.icsEngineAnalyze) {
\r
5741 ExitAnalyzeMode();
\r
5745 appData.icsEngineAnalyze = TRUE;
\r
5746 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5749 if (!appData.showThinking) ToggleShowThinking();
\r
5750 AnalyzeModeEvent();
\r
5754 case IDM_AnalyzeFile:
\r
5755 if (!first.analysisSupport) {
\r
5756 char buf[MSG_SIZ];
\r
5757 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5758 DisplayError(buf, 0);
\r
5760 if (!appData.showThinking) ToggleShowThinking();
\r
5761 AnalyzeFileEvent();
\r
5762 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5763 AnalysisPeriodicEvent(1);
\r
5767 case IDM_IcsClient:
\r
5771 case IDM_EditGame:
\r
5776 case IDM_EditPosition:
\r
5777 EditPositionEvent();
\r
5778 SAY("to set up a position type a FEN");
\r
5781 case IDM_Training:
\r
5785 case IDM_ShowGameList:
\r
5786 ShowGameListProc();
\r
5789 case IDM_EditTags:
\r
5793 case IDM_EditComment:
\r
5794 if (commentUp && editComment) {
\r
5797 EditCommentEvent();
\r
5817 case IDM_CallFlag:
\r
5837 case IDM_StopObserving:
\r
5838 StopObservingEvent();
\r
5841 case IDM_StopExamining:
\r
5842 StopExaminingEvent();
\r
5845 case IDM_TypeInMove:
\r
5846 PopUpMoveDialog('\000');
\r
5849 case IDM_TypeInName:
\r
5850 PopUpNameDialog('\000');
\r
5853 case IDM_Backward:
\r
5855 SetFocus(hwndMain);
\r
5862 SetFocus(hwndMain);
\r
5867 SetFocus(hwndMain);
\r
5872 SetFocus(hwndMain);
\r
5879 case IDM_TruncateGame:
\r
5880 TruncateGameEvent();
\r
5887 case IDM_RetractMove:
\r
5888 RetractMoveEvent();
\r
5891 case IDM_FlipView:
\r
5892 flipView = !flipView;
\r
5893 DrawPosition(FALSE, NULL);
\r
5896 case IDM_FlipClock:
\r
5897 flipClock = !flipClock;
\r
5898 DisplayBothClocks();
\r
5899 DrawPosition(FALSE, NULL);
\r
5902 case IDM_MuteSounds:
\r
5903 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5904 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5905 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5908 case IDM_GeneralOptions:
\r
5909 GeneralOptionsPopup(hwnd);
\r
5910 DrawPosition(TRUE, NULL);
\r
5913 case IDM_BoardOptions:
\r
5914 BoardOptionsPopup(hwnd);
\r
5917 case IDM_EnginePlayOptions:
\r
5918 EnginePlayOptionsPopup(hwnd);
\r
5921 case IDM_Engine1Options:
\r
5922 EngineOptionsPopup(hwnd, &first);
\r
5925 case IDM_Engine2Options:
\r
5926 EngineOptionsPopup(hwnd, &second);
\r
5929 case IDM_OptionsUCI:
\r
5930 UciOptionsPopup(hwnd);
\r
5933 case IDM_IcsOptions:
\r
5934 IcsOptionsPopup(hwnd);
\r
5938 FontsOptionsPopup(hwnd);
\r
5942 SoundOptionsPopup(hwnd);
\r
5945 case IDM_CommPort:
\r
5946 CommPortOptionsPopup(hwnd);
\r
5949 case IDM_LoadOptions:
\r
5950 LoadOptionsPopup(hwnd);
\r
5953 case IDM_SaveOptions:
\r
5954 SaveOptionsPopup(hwnd);
\r
5957 case IDM_TimeControl:
\r
5958 TimeControlOptionsPopup(hwnd);
\r
5961 case IDM_SaveSettings:
\r
5962 SaveSettings(settingsFileName);
\r
5965 case IDM_SaveSettingsOnExit:
\r
5966 saveSettingsOnExit = !saveSettingsOnExit;
\r
5967 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5968 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5969 MF_CHECKED : MF_UNCHECKED));
\r
5980 case IDM_AboutGame:
\r
5985 appData.debugMode = !appData.debugMode;
\r
5986 if (appData.debugMode) {
\r
5987 char dir[MSG_SIZ];
\r
5988 GetCurrentDirectory(MSG_SIZ, dir);
\r
5989 SetCurrentDirectory(installDir);
\r
5990 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5991 SetCurrentDirectory(dir);
\r
5992 setbuf(debugFP, NULL);
\r
5999 case IDM_HELPCONTENTS:
\r
6000 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6001 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6002 MessageBox (GetFocus(),
\r
6003 "Unable to activate help",
\r
6004 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6008 case IDM_HELPSEARCH:
\r
6009 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6010 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6011 MessageBox (GetFocus(),
\r
6012 "Unable to activate help",
\r
6013 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6017 case IDM_HELPHELP:
\r
6018 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6019 MessageBox (GetFocus(),
\r
6020 "Unable to activate help",
\r
6021 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6026 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6028 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6029 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6030 FreeProcInstance(lpProc);
\r
6033 case IDM_DirectCommand1:
\r
6034 AskQuestionEvent("Direct Command",
\r
6035 "Send to chess program:", "", "1");
\r
6037 case IDM_DirectCommand2:
\r
6038 AskQuestionEvent("Direct Command",
\r
6039 "Send to second chess program:", "", "2");
\r
6042 case EP_WhitePawn:
\r
6043 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6044 fromX = fromY = -1;
\r
6047 case EP_WhiteKnight:
\r
6048 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6049 fromX = fromY = -1;
\r
6052 case EP_WhiteBishop:
\r
6053 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6054 fromX = fromY = -1;
\r
6057 case EP_WhiteRook:
\r
6058 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6059 fromX = fromY = -1;
\r
6062 case EP_WhiteQueen:
\r
6063 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6064 fromX = fromY = -1;
\r
6067 case EP_WhiteFerz:
\r
6068 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6069 fromX = fromY = -1;
\r
6072 case EP_WhiteWazir:
\r
6073 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6074 fromX = fromY = -1;
\r
6077 case EP_WhiteAlfil:
\r
6078 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6079 fromX = fromY = -1;
\r
6082 case EP_WhiteCannon:
\r
6083 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6084 fromX = fromY = -1;
\r
6087 case EP_WhiteCardinal:
\r
6088 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6089 fromX = fromY = -1;
\r
6092 case EP_WhiteMarshall:
\r
6093 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6094 fromX = fromY = -1;
\r
6097 case EP_WhiteKing:
\r
6098 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6099 fromX = fromY = -1;
\r
6102 case EP_BlackPawn:
\r
6103 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6104 fromX = fromY = -1;
\r
6107 case EP_BlackKnight:
\r
6108 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6109 fromX = fromY = -1;
\r
6112 case EP_BlackBishop:
\r
6113 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6114 fromX = fromY = -1;
\r
6117 case EP_BlackRook:
\r
6118 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6119 fromX = fromY = -1;
\r
6122 case EP_BlackQueen:
\r
6123 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6124 fromX = fromY = -1;
\r
6127 case EP_BlackFerz:
\r
6128 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6129 fromX = fromY = -1;
\r
6132 case EP_BlackWazir:
\r
6133 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6134 fromX = fromY = -1;
\r
6137 case EP_BlackAlfil:
\r
6138 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6139 fromX = fromY = -1;
\r
6142 case EP_BlackCannon:
\r
6143 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6144 fromX = fromY = -1;
\r
6147 case EP_BlackCardinal:
\r
6148 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6149 fromX = fromY = -1;
\r
6152 case EP_BlackMarshall:
\r
6153 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6154 fromX = fromY = -1;
\r
6157 case EP_BlackKing:
\r
6158 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6159 fromX = fromY = -1;
\r
6162 case EP_EmptySquare:
\r
6163 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6164 fromX = fromY = -1;
\r
6167 case EP_ClearBoard:
\r
6168 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6169 fromX = fromY = -1;
\r
6173 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6174 fromX = fromY = -1;
\r
6178 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6179 fromX = fromY = -1;
\r
6183 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6184 fromX = fromY = -1;
\r
6188 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6189 fromX = fromY = -1;
\r
6193 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6194 fromX = fromY = -1;
\r
6198 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6199 fromX = fromY = -1;
\r
6203 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6204 fromX = fromY = -1;
\r
6208 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6209 fromX = fromY = -1;
\r
6213 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6214 fromX = fromY = -1;
\r
6218 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6224 case CLOCK_TIMER_ID:
\r
6225 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6226 clockTimerEvent = 0;
\r
6227 DecrementClocks(); /* call into back end */
\r
6229 case LOAD_GAME_TIMER_ID:
\r
6230 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6231 loadGameTimerEvent = 0;
\r
6232 AutoPlayGameLoop(); /* call into back end */
\r
6234 case ANALYSIS_TIMER_ID:
\r
6235 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6236 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6237 AnalysisPeriodicEvent(0);
\r
6239 KillTimer(hwnd, analysisTimerEvent);
\r
6240 analysisTimerEvent = 0;
\r
6243 case DELAYED_TIMER_ID:
\r
6244 KillTimer(hwnd, delayedTimerEvent);
\r
6245 delayedTimerEvent = 0;
\r
6246 delayedTimerCallback();
\r
6251 case WM_USER_Input:
\r
6252 InputEvent(hwnd, message, wParam, lParam);
\r
6255 /* [AS] Also move "attached" child windows */
\r
6256 case WM_WINDOWPOSCHANGING:
\r
6258 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6259 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6261 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6262 /* Window is moving */
\r
6265 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6266 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6267 rcMain.right = boardX + winWidth;
\r
6268 rcMain.top = boardY;
\r
6269 rcMain.bottom = boardY + winHeight;
\r
6271 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6272 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6273 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6274 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6275 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6282 /* [AS] Snapping */
\r
6283 case WM_ENTERSIZEMOVE:
\r
6284 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6285 if (hwnd == hwndMain) {
\r
6286 doingSizing = TRUE;
\r
6289 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6293 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6294 if (hwnd == hwndMain) {
\r
6295 lastSizing = wParam;
\r
6300 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6301 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6303 case WM_EXITSIZEMOVE:
\r
6304 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6305 if (hwnd == hwndMain) {
\r
6307 doingSizing = FALSE;
\r
6308 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6309 GetClientRect(hwnd, &client);
\r
6310 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6312 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6314 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6317 case WM_DESTROY: /* message: window being destroyed */
\r
6318 PostQuitMessage(0);
\r
6322 if (hwnd == hwndMain) {
\r
6327 default: /* Passes it on if unprocessed */
\r
6328 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6333 /*---------------------------------------------------------------------------*\
\r
6335 * Misc utility routines
\r
6337 \*---------------------------------------------------------------------------*/
\r
6340 * Decent random number generator, at least not as bad as Windows
\r
6341 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6343 unsigned int randstate;
\r
6348 randstate = randstate * 1664525 + 1013904223;
\r
6349 return (int) randstate & 0x7fffffff;
\r
6353 mysrandom(unsigned int seed)
\r
6360 * returns TRUE if user selects a different color, FALSE otherwise
\r
6364 ChangeColor(HWND hwnd, COLORREF *which)
\r
6366 static BOOL firstTime = TRUE;
\r
6367 static DWORD customColors[16];
\r
6369 COLORREF newcolor;
\r
6374 /* Make initial colors in use available as custom colors */
\r
6375 /* Should we put the compiled-in defaults here instead? */
\r
6377 customColors[i++] = lightSquareColor & 0xffffff;
\r
6378 customColors[i++] = darkSquareColor & 0xffffff;
\r
6379 customColors[i++] = whitePieceColor & 0xffffff;
\r
6380 customColors[i++] = blackPieceColor & 0xffffff;
\r
6381 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6382 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6384 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6385 customColors[i++] = textAttribs[ccl].color;
\r
6387 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6388 firstTime = FALSE;
\r
6391 cc.lStructSize = sizeof(cc);
\r
6392 cc.hwndOwner = hwnd;
\r
6393 cc.hInstance = NULL;
\r
6394 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6395 cc.lpCustColors = (LPDWORD) customColors;
\r
6396 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6398 if (!ChooseColor(&cc)) return FALSE;
\r
6400 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6401 if (newcolor == *which) return FALSE;
\r
6402 *which = newcolor;
\r
6406 InitDrawingColors();
\r
6407 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6412 MyLoadSound(MySound *ms)
\r
6418 if (ms->data) free(ms->data);
\r
6421 switch (ms->name[0]) {
\r
6427 /* System sound from Control Panel. Don't preload here. */
\r
6431 if (ms->name[1] == NULLCHAR) {
\r
6432 /* "!" alone = silence */
\r
6435 /* Builtin wave resource. Error if not found. */
\r
6436 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6437 if (h == NULL) break;
\r
6438 ms->data = (void *)LoadResource(hInst, h);
\r
6439 if (h == NULL) break;
\r
6444 /* .wav file. Error if not found. */
\r
6445 f = fopen(ms->name, "rb");
\r
6446 if (f == NULL) break;
\r
6447 if (fstat(fileno(f), &st) < 0) break;
\r
6448 ms->data = malloc(st.st_size);
\r
6449 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6455 char buf[MSG_SIZ];
\r
6456 sprintf(buf, "Error loading sound %s", ms->name);
\r
6457 DisplayError(buf, GetLastError());
\r
6463 MyPlaySound(MySound *ms)
\r
6465 BOOLEAN ok = FALSE;
\r
6467 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6468 switch (ms->name[0]) {
\r
6470 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6475 /* System sound from Control Panel (deprecated feature).
\r
6476 "$" alone or an unset sound name gets default beep (still in use). */
\r
6477 if (ms->name[1]) {
\r
6478 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6480 if (!ok) ok = MessageBeep(MB_OK);
\r
6483 /* Builtin wave resource, or "!" alone for silence */
\r
6484 if (ms->name[1]) {
\r
6485 if (ms->data == NULL) return FALSE;
\r
6486 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6492 /* .wav file. Error if not found. */
\r
6493 if (ms->data == NULL) return FALSE;
\r
6494 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6497 /* Don't print an error: this can happen innocently if the sound driver
\r
6498 is busy; for instance, if another instance of WinBoard is playing
\r
6499 a sound at about the same time. */
\r
6505 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6508 OPENFILENAME *ofn;
\r
6509 static UINT *number; /* gross that this is static */
\r
6511 switch (message) {
\r
6512 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6513 /* Center the dialog over the application window */
\r
6514 ofn = (OPENFILENAME *) lParam;
\r
6515 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6516 number = (UINT *) ofn->lCustData;
\r
6517 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6521 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6522 return FALSE; /* Allow for further processing */
\r
6525 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6526 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6528 return FALSE; /* Allow for further processing */
\r
6534 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6536 static UINT *number;
\r
6537 OPENFILENAME *ofname;
\r
6540 case WM_INITDIALOG:
\r
6541 ofname = (OPENFILENAME *)lParam;
\r
6542 number = (UINT *)(ofname->lCustData);
\r
6545 ofnot = (OFNOTIFY *)lParam;
\r
6546 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6547 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6556 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6557 char *nameFilt, char *dlgTitle, UINT *number,
\r
6558 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6560 OPENFILENAME openFileName;
\r
6561 char buf1[MSG_SIZ];
\r
6564 if (fileName == NULL) fileName = buf1;
\r
6565 if (defName == NULL) {
\r
6566 strcpy(fileName, "*.");
\r
6567 strcat(fileName, defExt);
\r
6569 strcpy(fileName, defName);
\r
6571 if (fileTitle) strcpy(fileTitle, "");
\r
6572 if (number) *number = 0;
\r
6574 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6575 openFileName.hwndOwner = hwnd;
\r
6576 openFileName.hInstance = (HANDLE) hInst;
\r
6577 openFileName.lpstrFilter = nameFilt;
\r
6578 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6579 openFileName.nMaxCustFilter = 0L;
\r
6580 openFileName.nFilterIndex = 1L;
\r
6581 openFileName.lpstrFile = fileName;
\r
6582 openFileName.nMaxFile = MSG_SIZ;
\r
6583 openFileName.lpstrFileTitle = fileTitle;
\r
6584 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6585 openFileName.lpstrInitialDir = NULL;
\r
6586 openFileName.lpstrTitle = dlgTitle;
\r
6587 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6588 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6589 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6590 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6591 openFileName.nFileOffset = 0;
\r
6592 openFileName.nFileExtension = 0;
\r
6593 openFileName.lpstrDefExt = defExt;
\r
6594 openFileName.lCustData = (LONG) number;
\r
6595 openFileName.lpfnHook = oldDialog ?
\r
6596 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6597 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6599 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6600 GetOpenFileName(&openFileName)) {
\r
6601 /* open the file */
\r
6602 f = fopen(openFileName.lpstrFile, write);
\r
6604 MessageBox(hwnd, "File open failed", NULL,
\r
6605 MB_OK|MB_ICONEXCLAMATION);
\r
6609 int err = CommDlgExtendedError();
\r
6610 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6619 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6621 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6624 * Get the first pop-up menu in the menu template. This is the
\r
6625 * menu that TrackPopupMenu displays.
\r
6627 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6629 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6632 * TrackPopup uses screen coordinates, so convert the
\r
6633 * coordinates of the mouse click to screen coordinates.
\r
6635 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6637 /* Draw and track the floating pop-up menu. */
\r
6638 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6639 pt.x, pt.y, 0, hwnd, NULL);
\r
6641 /* Destroy the menu.*/
\r
6642 DestroyMenu(hmenu);
\r
6647 int sizeX, sizeY, newSizeX, newSizeY;
\r
6649 } ResizeEditPlusButtonsClosure;
\r
6652 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6654 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6658 if (hChild == cl->hText) return TRUE;
\r
6659 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6660 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6661 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6662 ScreenToClient(cl->hDlg, &pt);
\r
6663 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6664 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6668 /* Resize a dialog that has a (rich) edit field filling most of
\r
6669 the top, with a row of buttons below */
\r
6671 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6674 int newTextHeight, newTextWidth;
\r
6675 ResizeEditPlusButtonsClosure cl;
\r
6677 /*if (IsIconic(hDlg)) return;*/
\r
6678 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6680 cl.hdwp = BeginDeferWindowPos(8);
\r
6682 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6683 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6684 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6685 if (newTextHeight < 0) {
\r
6686 newSizeY += -newTextHeight;
\r
6687 newTextHeight = 0;
\r
6689 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6690 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6696 cl.newSizeX = newSizeX;
\r
6697 cl.newSizeY = newSizeY;
\r
6698 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6700 EndDeferWindowPos(cl.hdwp);
\r
6703 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6705 RECT rChild, rParent;
\r
6706 int wChild, hChild, wParent, hParent;
\r
6707 int wScreen, hScreen, xNew, yNew;
\r
6710 /* Get the Height and Width of the child window */
\r
6711 GetWindowRect (hwndChild, &rChild);
\r
6712 wChild = rChild.right - rChild.left;
\r
6713 hChild = rChild.bottom - rChild.top;
\r
6715 /* Get the Height and Width of the parent window */
\r
6716 GetWindowRect (hwndParent, &rParent);
\r
6717 wParent = rParent.right - rParent.left;
\r
6718 hParent = rParent.bottom - rParent.top;
\r
6720 /* Get the display limits */
\r
6721 hdc = GetDC (hwndChild);
\r
6722 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6723 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6724 ReleaseDC(hwndChild, hdc);
\r
6726 /* Calculate new X position, then adjust for screen */
\r
6727 xNew = rParent.left + ((wParent - wChild) /2);
\r
6730 } else if ((xNew+wChild) > wScreen) {
\r
6731 xNew = wScreen - wChild;
\r
6734 /* Calculate new Y position, then adjust for screen */
\r
6736 yNew = rParent.top + ((hParent - hChild) /2);
\r
6739 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6744 } else if ((yNew+hChild) > hScreen) {
\r
6745 yNew = hScreen - hChild;
\r
6748 /* Set it, and return */
\r
6749 return SetWindowPos (hwndChild, NULL,
\r
6750 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6753 /* Center one window over another */
\r
6754 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6756 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6759 /*---------------------------------------------------------------------------*\
\r
6761 * Startup Dialog functions
\r
6763 \*---------------------------------------------------------------------------*/
\r
6765 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6767 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6769 while (*cd != NULL) {
\r
6770 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6776 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6778 char buf1[ARG_MAX];
\r
6781 if (str[0] == '@') {
\r
6782 FILE* f = fopen(str + 1, "r");
\r
6784 DisplayFatalError(str + 1, errno, 2);
\r
6787 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6789 buf1[len] = NULLCHAR;
\r
6793 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6796 char buf[MSG_SIZ];
\r
6797 char *end = strchr(str, '\n');
\r
6798 if (end == NULL) return;
\r
6799 memcpy(buf, str, end - str);
\r
6800 buf[end - str] = NULLCHAR;
\r
6801 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6807 SetStartupDialogEnables(HWND hDlg)
\r
6809 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6810 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6811 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6812 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6813 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6814 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6815 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6816 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6817 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6818 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6819 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6820 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6821 IsDlgButtonChecked(hDlg, OPT_View));
\r
6825 QuoteForFilename(char *filename)
\r
6827 int dquote, space;
\r
6828 dquote = strchr(filename, '"') != NULL;
\r
6829 space = strchr(filename, ' ') != NULL;
\r
6830 if (dquote || space) {
\r
6842 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6844 char buf[MSG_SIZ];
\r
6847 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6848 q = QuoteForFilename(nthcp);
\r
6849 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6850 if (*nthdir != NULLCHAR) {
\r
6851 q = QuoteForFilename(nthdir);
\r
6852 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6854 if (*nthcp == NULLCHAR) {
\r
6855 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6856 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6857 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6858 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6863 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6865 char buf[MSG_SIZ];
\r
6869 switch (message) {
\r
6870 case WM_INITDIALOG:
\r
6871 /* Center the dialog */
\r
6872 CenterWindow (hDlg, GetDesktopWindow());
\r
6873 /* Initialize the dialog items */
\r
6874 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6875 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6876 firstChessProgramNames);
\r
6877 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6878 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6879 secondChessProgramNames);
\r
6880 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6881 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6882 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6883 if (*appData.icsHelper != NULLCHAR) {
\r
6884 char *q = QuoteForFilename(appData.icsHelper);
\r
6885 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6887 if (*appData.icsHost == NULLCHAR) {
\r
6888 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6889 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6890 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6891 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6892 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6895 if (appData.icsActive) {
\r
6896 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6898 else if (appData.noChessProgram) {
\r
6899 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6902 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6905 SetStartupDialogEnables(hDlg);
\r
6909 switch (LOWORD(wParam)) {
\r
6911 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6912 strcpy(buf, "/fcp=");
\r
6913 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6915 ParseArgs(StringGet, &p);
\r
6916 strcpy(buf, "/scp=");
\r
6917 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6919 ParseArgs(StringGet, &p);
\r
6920 appData.noChessProgram = FALSE;
\r
6921 appData.icsActive = FALSE;
\r
6922 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6923 strcpy(buf, "/ics /icshost=");
\r
6924 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6926 ParseArgs(StringGet, &p);
\r
6927 if (appData.zippyPlay) {
\r
6928 strcpy(buf, "/fcp=");
\r
6929 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6931 ParseArgs(StringGet, &p);
\r
6933 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6934 appData.noChessProgram = TRUE;
\r
6935 appData.icsActive = FALSE;
\r
6937 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6938 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6941 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6942 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6944 ParseArgs(StringGet, &p);
\r
6946 EndDialog(hDlg, TRUE);
\r
6953 case IDM_HELPCONTENTS:
\r
6954 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6955 MessageBox (GetFocus(),
\r
6956 "Unable to activate help",
\r
6957 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6962 SetStartupDialogEnables(hDlg);
\r
6970 /*---------------------------------------------------------------------------*\
\r
6972 * About box dialog functions
\r
6974 \*---------------------------------------------------------------------------*/
\r
6976 /* Process messages for "About" dialog box */
\r
6978 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6980 switch (message) {
\r
6981 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6982 /* Center the dialog over the application window */
\r
6983 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6984 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6988 case WM_COMMAND: /* message: received a command */
\r
6989 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6990 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6991 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6999 /*---------------------------------------------------------------------------*\
\r
7001 * Comment Dialog functions
\r
7003 \*---------------------------------------------------------------------------*/
\r
7006 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7008 static HANDLE hwndText = NULL;
\r
7009 int len, newSizeX, newSizeY, flags;
\r
7010 static int sizeX, sizeY;
\r
7015 switch (message) {
\r
7016 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7017 /* Initialize the dialog items */
\r
7018 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7019 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7020 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7021 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7022 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7023 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7024 SetWindowText(hDlg, commentTitle);
\r
7025 if (editComment) {
\r
7026 SetFocus(hwndText);
\r
7028 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7030 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7031 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7032 MAKELPARAM(FALSE, 0));
\r
7033 /* Size and position the dialog */
\r
7034 if (!commentDialog) {
\r
7035 commentDialog = hDlg;
\r
7036 flags = SWP_NOZORDER;
\r
7037 GetClientRect(hDlg, &rect);
\r
7038 sizeX = rect.right;
\r
7039 sizeY = rect.bottom;
\r
7040 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7041 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7042 WINDOWPLACEMENT wp;
\r
7043 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7044 wp.length = sizeof(WINDOWPLACEMENT);
\r
7046 wp.showCmd = SW_SHOW;
\r
7047 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7048 wp.rcNormalPosition.left = commentX;
\r
7049 wp.rcNormalPosition.right = commentX + commentW;
\r
7050 wp.rcNormalPosition.top = commentY;
\r
7051 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7052 SetWindowPlacement(hDlg, &wp);
\r
7054 GetClientRect(hDlg, &rect);
\r
7055 newSizeX = rect.right;
\r
7056 newSizeY = rect.bottom;
\r
7057 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7058 newSizeX, newSizeY);
\r
7065 case WM_COMMAND: /* message: received a command */
\r
7066 switch (LOWORD(wParam)) {
\r
7068 if (editComment) {
\r
7070 /* Read changed options from the dialog box */
\r
7071 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7072 len = GetWindowTextLength(hwndText);
\r
7073 str = (char *) malloc(len + 1);
\r
7074 GetWindowText(hwndText, str, len + 1);
\r
7083 ReplaceComment(commentIndex, str);
\r
7090 case OPT_CancelComment:
\r
7094 case OPT_ClearComment:
\r
7095 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7098 case OPT_EditComment:
\r
7099 EditCommentEvent();
\r
7108 newSizeX = LOWORD(lParam);
\r
7109 newSizeY = HIWORD(lParam);
\r
7110 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7115 case WM_GETMINMAXINFO:
\r
7116 /* Prevent resizing window too small */
\r
7117 mmi = (MINMAXINFO *) lParam;
\r
7118 mmi->ptMinTrackSize.x = 100;
\r
7119 mmi->ptMinTrackSize.y = 100;
\r
7126 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7131 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7133 if (str == NULL) str = "";
\r
7134 p = (char *) malloc(2 * strlen(str) + 2);
\r
7137 if (*str == '\n') *q++ = '\r';
\r
7141 if (commentText != NULL) free(commentText);
\r
7143 commentIndex = index;
\r
7144 commentTitle = title;
\r
7146 editComment = edit;
\r
7148 if (commentDialog) {
\r
7149 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7150 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
7152 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7153 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7154 hwndMain, (DLGPROC)lpProc);
\r
7155 FreeProcInstance(lpProc);
\r
7161 /*---------------------------------------------------------------------------*\
\r
7163 * Type-in move dialog functions
\r
7165 \*---------------------------------------------------------------------------*/
\r
7168 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7170 char move[MSG_SIZ];
\r
7172 ChessMove moveType;
\r
7173 int fromX, fromY, toX, toY;
\r
7176 switch (message) {
\r
7177 case WM_INITDIALOG:
\r
7178 move[0] = (char) lParam;
\r
7179 move[1] = NULLCHAR;
\r
7180 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7181 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7182 SetWindowText(hInput, move);
\r
7184 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7188 switch (LOWORD(wParam)) {
\r
7190 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7191 { int n; Board board;
\r
7193 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7194 EditPositionPasteFEN(move);
\r
7195 EndDialog(hDlg, TRUE);
\r
7198 // [HGM] movenum: allow move number to be typed in any mode
\r
7199 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7201 EndDialog(hDlg, TRUE);
\r
7205 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7206 gameMode != Training) {
\r
7207 DisplayMoveError("Displayed move is not current");
\r
7209 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7210 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7211 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7212 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7213 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7214 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7215 if (gameMode != Training)
\r
7216 forwardMostMove = currentMove;
\r
7217 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7219 DisplayMoveError("Could not parse move");
\r
7222 EndDialog(hDlg, TRUE);
\r
7225 EndDialog(hDlg, FALSE);
\r
7236 PopUpMoveDialog(char firstchar)
\r
7240 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7241 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7242 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7243 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7244 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7245 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7246 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7247 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7248 gameMode == Training) {
\r
7249 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7250 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7251 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7252 FreeProcInstance(lpProc);
\r
7256 /*---------------------------------------------------------------------------*\
\r
7258 * Type-in name dialog functions
\r
7260 \*---------------------------------------------------------------------------*/
\r
7263 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7265 char move[MSG_SIZ];
\r
7268 switch (message) {
\r
7269 case WM_INITDIALOG:
\r
7270 move[0] = (char) lParam;
\r
7271 move[1] = NULLCHAR;
\r
7272 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7273 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7274 SetWindowText(hInput, move);
\r
7276 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7280 switch (LOWORD(wParam)) {
\r
7282 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7283 appData.userName = strdup(move);
\r
7286 EndDialog(hDlg, TRUE);
\r
7289 EndDialog(hDlg, FALSE);
\r
7300 PopUpNameDialog(char firstchar)
\r
7304 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7305 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7306 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7307 FreeProcInstance(lpProc);
\r
7310 /*---------------------------------------------------------------------------*\
\r
7314 \*---------------------------------------------------------------------------*/
\r
7316 /* Nonmodal error box */
\r
7317 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7318 WPARAM wParam, LPARAM lParam);
\r
7321 ErrorPopUp(char *title, char *content)
\r
7325 BOOLEAN modal = hwndMain == NULL;
\r
7343 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7344 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7347 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7349 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7350 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7351 hwndMain, (DLGPROC)lpProc);
\r
7352 FreeProcInstance(lpProc);
\r
7359 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7360 if (errorDialog == NULL) return;
\r
7361 DestroyWindow(errorDialog);
\r
7362 errorDialog = NULL;
\r
7366 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7371 switch (message) {
\r
7372 case WM_INITDIALOG:
\r
7373 GetWindowRect(hDlg, &rChild);
\r
7376 SetWindowPos(hDlg, NULL, rChild.left,
\r
7377 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7378 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7382 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7383 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7384 and it doesn't work when you resize the dialog.
\r
7385 For now, just give it a default position.
\r
7387 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7389 errorDialog = hDlg;
\r
7390 SetWindowText(hDlg, errorTitle);
\r
7391 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7392 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7396 switch (LOWORD(wParam)) {
\r
7399 if (errorDialog == hDlg) errorDialog = NULL;
\r
7400 DestroyWindow(hDlg);
\r
7412 HWND gothicDialog = NULL;
\r
7415 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7419 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7421 switch (message) {
\r
7422 case WM_INITDIALOG:
\r
7423 GetWindowRect(hDlg, &rChild);
\r
7425 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7429 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7430 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7431 and it doesn't work when you resize the dialog.
\r
7432 For now, just give it a default position.
\r
7434 gothicDialog = hDlg;
\r
7435 SetWindowText(hDlg, errorTitle);
\r
7436 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7437 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7441 switch (LOWORD(wParam)) {
\r
7444 if (errorDialog == hDlg) errorDialog = NULL;
\r
7445 DestroyWindow(hDlg);
\r
7457 GothicPopUp(char *title, VariantClass variant)
\r
7460 static char *lastTitle;
\r
7462 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7463 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7465 if(lastTitle != title && gothicDialog != NULL) {
\r
7466 DestroyWindow(gothicDialog);
\r
7467 gothicDialog = NULL;
\r
7469 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7470 title = lastTitle;
\r
7471 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7472 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7473 hwndMain, (DLGPROC)lpProc);
\r
7474 FreeProcInstance(lpProc);
\r
7479 /*---------------------------------------------------------------------------*\
\r
7481 * Ics Interaction console functions
\r
7483 \*---------------------------------------------------------------------------*/
\r
7485 #define HISTORY_SIZE 64
\r
7486 static char *history[HISTORY_SIZE];
\r
7487 int histIn = 0, histP = 0;
\r
7490 SaveInHistory(char *cmd)
\r
7492 if (history[histIn] != NULL) {
\r
7493 free(history[histIn]);
\r
7494 history[histIn] = NULL;
\r
7496 if (*cmd == NULLCHAR) return;
\r
7497 history[histIn] = StrSave(cmd);
\r
7498 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7499 if (history[histIn] != NULL) {
\r
7500 free(history[histIn]);
\r
7501 history[histIn] = NULL;
\r
7507 PrevInHistory(char *cmd)
\r
7510 if (histP == histIn) {
\r
7511 if (history[histIn] != NULL) free(history[histIn]);
\r
7512 history[histIn] = StrSave(cmd);
\r
7514 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7515 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7517 return history[histP];
\r
7523 if (histP == histIn) return NULL;
\r
7524 histP = (histP + 1) % HISTORY_SIZE;
\r
7525 return history[histP];
\r
7532 BOOLEAN immediate;
\r
7533 } IcsTextMenuEntry;
\r
7534 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7535 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7538 ParseIcsTextMenu(char *icsTextMenuString)
\r
7541 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7542 char *p = icsTextMenuString;
\r
7543 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7546 if (e->command != NULL) {
\r
7548 e->command = NULL;
\r
7552 e = icsTextMenuEntry;
\r
7553 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7554 if (*p == ';' || *p == '\n') {
\r
7555 e->item = strdup("-");
\r
7556 e->command = NULL;
\r
7558 } else if (*p == '-') {
\r
7559 e->item = strdup("-");
\r
7560 e->command = NULL;
\r
7564 char *q, *r, *s, *t;
\r
7566 q = strchr(p, ',');
\r
7567 if (q == NULL) break;
\r
7569 r = strchr(q + 1, ',');
\r
7570 if (r == NULL) break;
\r
7572 s = strchr(r + 1, ',');
\r
7573 if (s == NULL) break;
\r
7576 t = strchr(s + 1, c);
\r
7579 t = strchr(s + 1, c);
\r
7581 if (t != NULL) *t = NULLCHAR;
\r
7582 e->item = strdup(p);
\r
7583 e->command = strdup(q + 1);
\r
7584 e->getname = *(r + 1) != '0';
\r
7585 e->immediate = *(s + 1) != '0';
\r
7589 if (t == NULL) break;
\r
7598 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7602 hmenu = LoadMenu(hInst, "TextMenu");
\r
7603 h = GetSubMenu(hmenu, 0);
\r
7605 if (strcmp(e->item, "-") == 0) {
\r
7606 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7608 if (e->item[0] == '|') {
\r
7609 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7610 IDM_CommandX + i, &e->item[1]);
\r
7612 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7621 WNDPROC consoleTextWindowProc;
\r
7624 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7626 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7627 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7631 SetWindowText(hInput, command);
\r
7633 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7635 sel.cpMin = 999999;
\r
7636 sel.cpMax = 999999;
\r
7637 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7642 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7643 if (sel.cpMin == sel.cpMax) {
\r
7644 /* Expand to surrounding word */
\r
7647 tr.chrg.cpMax = sel.cpMin;
\r
7648 tr.chrg.cpMin = --sel.cpMin;
\r
7649 if (sel.cpMin < 0) break;
\r
7650 tr.lpstrText = name;
\r
7651 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7652 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7656 tr.chrg.cpMin = sel.cpMax;
\r
7657 tr.chrg.cpMax = ++sel.cpMax;
\r
7658 tr.lpstrText = name;
\r
7659 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7660 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7663 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7664 MessageBeep(MB_ICONEXCLAMATION);
\r
7668 tr.lpstrText = name;
\r
7669 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7671 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7672 MessageBeep(MB_ICONEXCLAMATION);
\r
7675 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7678 sprintf(buf, "%s %s", command, name);
\r
7679 SetWindowText(hInput, buf);
\r
7680 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7682 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7683 SetWindowText(hInput, buf);
\r
7684 sel.cpMin = 999999;
\r
7685 sel.cpMax = 999999;
\r
7686 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7692 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7697 switch (message) {
\r
7699 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7702 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7705 sel.cpMin = 999999;
\r
7706 sel.cpMax = 999999;
\r
7707 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7708 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7713 if(wParam != '\022') {
\r
7714 if (wParam == '\t') {
\r
7715 if (GetKeyState(VK_SHIFT) < 0) {
\r
7717 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7718 if (buttonDesc[0].hwnd) {
\r
7719 SetFocus(buttonDesc[0].hwnd);
\r
7721 SetFocus(hwndMain);
\r
7725 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7728 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7729 JAWS_DELETE( SetFocus(hInput); )
\r
7730 SendMessage(hInput, message, wParam, lParam);
\r
7733 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7734 case WM_RBUTTONUP:
\r
7735 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7736 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7737 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7740 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7741 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7742 if (sel.cpMin == sel.cpMax) {
\r
7743 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7744 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7746 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7747 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7749 pt.x = LOWORD(lParam);
\r
7750 pt.y = HIWORD(lParam);
\r
7751 MenuPopup(hwnd, pt, hmenu, -1);
\r
7755 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7757 return SendMessage(hInput, message, wParam, lParam);
\r
7758 case WM_MBUTTONDOWN:
\r
7759 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7760 case WM_RBUTTONDOWN:
\r
7761 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7762 /* Move selection here if it was empty */
\r
7764 pt.x = LOWORD(lParam);
\r
7765 pt.y = HIWORD(lParam);
\r
7766 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7767 if (sel.cpMin == sel.cpMax) {
\r
7768 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7769 sel.cpMax = sel.cpMin;
\r
7770 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7772 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7776 switch (LOWORD(wParam)) {
\r
7777 case IDM_QuickPaste:
\r
7779 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7780 if (sel.cpMin == sel.cpMax) {
\r
7781 MessageBeep(MB_ICONEXCLAMATION);
\r
7784 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7785 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7786 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7791 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7794 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7797 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7801 int i = LOWORD(wParam) - IDM_CommandX;
\r
7802 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7803 icsTextMenuEntry[i].command != NULL) {
\r
7804 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7805 icsTextMenuEntry[i].getname,
\r
7806 icsTextMenuEntry[i].immediate);
\r
7814 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7817 WNDPROC consoleInputWindowProc;
\r
7820 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7822 char buf[MSG_SIZ];
\r
7824 static BOOL sendNextChar = FALSE;
\r
7825 static BOOL quoteNextChar = FALSE;
\r
7826 InputSource *is = consoleInputSource;
\r
7830 switch (message) {
\r
7832 if (!appData.localLineEditing || sendNextChar) {
\r
7833 is->buf[0] = (CHAR) wParam;
\r
7835 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7836 sendNextChar = FALSE;
\r
7839 if (quoteNextChar) {
\r
7840 buf[0] = (char) wParam;
\r
7841 buf[1] = NULLCHAR;
\r
7842 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7843 quoteNextChar = FALSE;
\r
7847 case '\r': /* Enter key */
\r
7848 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7849 if (consoleEcho) SaveInHistory(is->buf);
\r
7850 is->buf[is->count++] = '\n';
\r
7851 is->buf[is->count] = NULLCHAR;
\r
7852 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7853 if (consoleEcho) {
\r
7854 ConsoleOutput(is->buf, is->count, TRUE);
\r
7855 } else if (appData.localLineEditing) {
\r
7856 ConsoleOutput("\n", 1, TRUE);
\r
7859 case '\033': /* Escape key */
\r
7860 SetWindowText(hwnd, "");
\r
7861 cf.cbSize = sizeof(CHARFORMAT);
\r
7862 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7863 if (consoleEcho) {
\r
7864 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7866 cf.crTextColor = COLOR_ECHOOFF;
\r
7868 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7869 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7871 case '\t': /* Tab key */
\r
7872 if (GetKeyState(VK_SHIFT) < 0) {
\r
7874 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7877 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7878 if (buttonDesc[0].hwnd) {
\r
7879 SetFocus(buttonDesc[0].hwnd);
\r
7881 SetFocus(hwndMain);
\r
7885 case '\023': /* Ctrl+S */
\r
7886 sendNextChar = TRUE;
\r
7888 case '\021': /* Ctrl+Q */
\r
7889 quoteNextChar = TRUE;
\r
7899 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7900 p = PrevInHistory(buf);
\r
7902 SetWindowText(hwnd, p);
\r
7903 sel.cpMin = 999999;
\r
7904 sel.cpMax = 999999;
\r
7905 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7910 p = NextInHistory();
\r
7912 SetWindowText(hwnd, p);
\r
7913 sel.cpMin = 999999;
\r
7914 sel.cpMax = 999999;
\r
7915 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7921 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7925 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7929 case WM_MBUTTONDOWN:
\r
7930 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7931 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7933 case WM_RBUTTONUP:
\r
7934 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7935 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7936 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7940 hmenu = LoadMenu(hInst, "InputMenu");
\r
7941 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7942 if (sel.cpMin == sel.cpMax) {
\r
7943 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7944 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7946 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7947 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7949 pt.x = LOWORD(lParam);
\r
7950 pt.y = HIWORD(lParam);
\r
7951 MenuPopup(hwnd, pt, hmenu, -1);
\r
7955 switch (LOWORD(wParam)) {
\r
7957 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7959 case IDM_SelectAll:
\r
7961 sel.cpMax = -1; /*999999?*/
\r
7962 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7965 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7968 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7971 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7976 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7979 #define CO_MAX 100000
\r
7980 #define CO_TRIM 1000
\r
7983 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7985 static SnapData sd;
\r
7986 HWND hText, hInput;
\r
7988 static int sizeX, sizeY;
\r
7989 int newSizeX, newSizeY;
\r
7993 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7994 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7996 switch (message) {
\r
7998 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8000 ENLINK *pLink = (ENLINK*)lParam;
\r
8001 if (pLink->msg == WM_LBUTTONUP)
\r
8005 tr.chrg = pLink->chrg;
\r
8006 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8007 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8008 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8009 free(tr.lpstrText);
\r
8013 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8014 hwndConsole = hDlg;
\r
8016 consoleTextWindowProc = (WNDPROC)
\r
8017 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8018 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8019 consoleInputWindowProc = (WNDPROC)
\r
8020 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8021 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8022 Colorize(ColorNormal, TRUE);
\r
8023 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8024 ChangedConsoleFont();
\r
8025 GetClientRect(hDlg, &rect);
\r
8026 sizeX = rect.right;
\r
8027 sizeY = rect.bottom;
\r
8028 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8029 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8030 WINDOWPLACEMENT wp;
\r
8031 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8032 wp.length = sizeof(WINDOWPLACEMENT);
\r
8034 wp.showCmd = SW_SHOW;
\r
8035 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8036 wp.rcNormalPosition.left = wpConsole.x;
\r
8037 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8038 wp.rcNormalPosition.top = wpConsole.y;
\r
8039 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8040 SetWindowPlacement(hDlg, &wp);
\r
8043 // [HGM] Chessknight's change 2004-07-13
\r
8044 else { /* Determine Defaults */
\r
8045 WINDOWPLACEMENT wp;
\r
8046 wpConsole.x = winWidth + 1;
\r
8047 wpConsole.y = boardY;
\r
8048 wpConsole.width = screenWidth - winWidth;
\r
8049 wpConsole.height = winHeight;
\r
8050 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8051 wp.length = sizeof(WINDOWPLACEMENT);
\r
8053 wp.showCmd = SW_SHOW;
\r
8054 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8055 wp.rcNormalPosition.left = wpConsole.x;
\r
8056 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8057 wp.rcNormalPosition.top = wpConsole.y;
\r
8058 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8059 SetWindowPlacement(hDlg, &wp);
\r
8062 // Allow hText to highlight URLs and send notifications on them
\r
8063 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8064 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8065 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8066 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8080 if (IsIconic(hDlg)) break;
\r
8081 newSizeX = LOWORD(lParam);
\r
8082 newSizeY = HIWORD(lParam);
\r
8083 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8084 RECT rectText, rectInput;
\r
8086 int newTextHeight, newTextWidth;
\r
8087 GetWindowRect(hText, &rectText);
\r
8088 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8089 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8090 if (newTextHeight < 0) {
\r
8091 newSizeY += -newTextHeight;
\r
8092 newTextHeight = 0;
\r
8094 SetWindowPos(hText, NULL, 0, 0,
\r
8095 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8096 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8097 pt.x = rectInput.left;
\r
8098 pt.y = rectInput.top + newSizeY - sizeY;
\r
8099 ScreenToClient(hDlg, &pt);
\r
8100 SetWindowPos(hInput, NULL,
\r
8101 pt.x, pt.y, /* needs client coords */
\r
8102 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8103 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8109 case WM_GETMINMAXINFO:
\r
8110 /* Prevent resizing window too small */
\r
8111 mmi = (MINMAXINFO *) lParam;
\r
8112 mmi->ptMinTrackSize.x = 100;
\r
8113 mmi->ptMinTrackSize.y = 100;
\r
8116 /* [AS] Snapping */
\r
8117 case WM_ENTERSIZEMOVE:
\r
8118 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8121 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8124 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8126 case WM_EXITSIZEMOVE:
\r
8127 UpdateICSWidth(hText);
\r
8128 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8131 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8139 if (hwndConsole) return;
\r
8140 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8141 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8146 ConsoleOutput(char* data, int length, int forceVisible)
\r
8151 char buf[CO_MAX+1];
\r
8154 static int delayLF = 0;
\r
8155 CHARRANGE savesel, sel;
\r
8157 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8165 while (length--) {
\r
8173 } else if (*p == '\007') {
\r
8174 MyPlaySound(&sounds[(int)SoundBell]);
\r
8181 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8182 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8183 /* Save current selection */
\r
8184 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8185 exlen = GetWindowTextLength(hText);
\r
8186 /* Find out whether current end of text is visible */
\r
8187 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8188 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8189 /* Trim existing text if it's too long */
\r
8190 if (exlen + (q - buf) > CO_MAX) {
\r
8191 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8194 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8195 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8197 savesel.cpMin -= trim;
\r
8198 savesel.cpMax -= trim;
\r
8199 if (exlen < 0) exlen = 0;
\r
8200 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8201 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8203 /* Append the new text */
\r
8204 sel.cpMin = exlen;
\r
8205 sel.cpMax = exlen;
\r
8206 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8207 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8208 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8209 if (forceVisible || exlen == 0 ||
\r
8210 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8211 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8212 /* Scroll to make new end of text visible if old end of text
\r
8213 was visible or new text is an echo of user typein */
\r
8214 sel.cpMin = 9999999;
\r
8215 sel.cpMax = 9999999;
\r
8216 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8217 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8218 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8219 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8221 if (savesel.cpMax == exlen || forceVisible) {
\r
8222 /* Move insert point to new end of text if it was at the old
\r
8223 end of text or if the new text is an echo of user typein */
\r
8224 sel.cpMin = 9999999;
\r
8225 sel.cpMax = 9999999;
\r
8226 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8228 /* Restore previous selection */
\r
8229 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8231 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8238 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8242 COLORREF oldFg, oldBg;
\r
8246 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8248 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8249 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8250 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8253 rect.right = x + squareSize;
\r
8255 rect.bottom = y + squareSize;
\r
8258 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8259 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8260 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8261 &rect, str, strlen(str), NULL);
\r
8263 (void) SetTextColor(hdc, oldFg);
\r
8264 (void) SetBkColor(hdc, oldBg);
\r
8265 (void) SelectObject(hdc, oldFont);
\r
8269 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8270 RECT *rect, char *color, char *flagFell)
\r
8274 COLORREF oldFg, oldBg;
\r
8277 if (appData.clockMode) {
\r
8279 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8281 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8288 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8289 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8291 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8292 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8294 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8298 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8299 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8300 rect, str, strlen(str), NULL);
\r
8301 if(logoHeight > 0 && appData.clockMode) {
\r
8303 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8304 r.top = rect->top + logoHeight/2;
\r
8305 r.left = rect->left;
\r
8306 r.right = rect->right;
\r
8307 r.bottom = rect->bottom;
\r
8308 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8309 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8310 &r, str, strlen(str), NULL);
\r
8312 (void) SetTextColor(hdc, oldFg);
\r
8313 (void) SetBkColor(hdc, oldBg);
\r
8314 (void) SelectObject(hdc, oldFont);
\r
8319 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8325 if( count <= 0 ) {
\r
8326 if (appData.debugMode) {
\r
8327 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8330 return ERROR_INVALID_USER_BUFFER;
\r
8333 ResetEvent(ovl->hEvent);
\r
8334 ovl->Offset = ovl->OffsetHigh = 0;
\r
8335 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8339 err = GetLastError();
\r
8340 if (err == ERROR_IO_PENDING) {
\r
8341 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8345 err = GetLastError();
\r
8352 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8357 ResetEvent(ovl->hEvent);
\r
8358 ovl->Offset = ovl->OffsetHigh = 0;
\r
8359 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8363 err = GetLastError();
\r
8364 if (err == ERROR_IO_PENDING) {
\r
8365 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8369 err = GetLastError();
\r
8375 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8376 void CheckForInputBufferFull( InputSource * is )
\r
8378 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8379 /* Look for end of line */
\r
8380 char * p = is->buf;
\r
8382 while( p < is->next && *p != '\n' ) {
\r
8386 if( p >= is->next ) {
\r
8387 if (appData.debugMode) {
\r
8388 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8391 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8392 is->count = (DWORD) -1;
\r
8393 is->next = is->buf;
\r
8399 InputThread(LPVOID arg)
\r
8404 is = (InputSource *) arg;
\r
8405 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8406 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8407 while (is->hThread != NULL) {
\r
8408 is->error = DoReadFile(is->hFile, is->next,
\r
8409 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8410 &is->count, &ovl);
\r
8411 if (is->error == NO_ERROR) {
\r
8412 is->next += is->count;
\r
8414 if (is->error == ERROR_BROKEN_PIPE) {
\r
8415 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8418 is->count = (DWORD) -1;
\r
8419 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8424 CheckForInputBufferFull( is );
\r
8426 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8428 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8430 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8433 CloseHandle(ovl.hEvent);
\r
8434 CloseHandle(is->hFile);
\r
8436 if (appData.debugMode) {
\r
8437 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8444 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8446 NonOvlInputThread(LPVOID arg)
\r
8453 is = (InputSource *) arg;
\r
8454 while (is->hThread != NULL) {
\r
8455 is->error = ReadFile(is->hFile, is->next,
\r
8456 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8457 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8458 if (is->error == NO_ERROR) {
\r
8459 /* Change CRLF to LF */
\r
8460 if (is->next > is->buf) {
\r
8462 i = is->count + 1;
\r
8470 if (prev == '\r' && *p == '\n') {
\r
8482 if (is->error == ERROR_BROKEN_PIPE) {
\r
8483 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8486 is->count = (DWORD) -1;
\r
8490 CheckForInputBufferFull( is );
\r
8492 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8494 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8496 if (is->count < 0) break; /* Quit on error */
\r
8498 CloseHandle(is->hFile);
\r
8503 SocketInputThread(LPVOID arg)
\r
8507 is = (InputSource *) arg;
\r
8508 while (is->hThread != NULL) {
\r
8509 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8510 if ((int)is->count == SOCKET_ERROR) {
\r
8511 is->count = (DWORD) -1;
\r
8512 is->error = WSAGetLastError();
\r
8514 is->error = NO_ERROR;
\r
8515 is->next += is->count;
\r
8516 if (is->count == 0 && is->second == is) {
\r
8517 /* End of file on stderr; quit with no message */
\r
8521 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8523 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8525 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8531 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8535 is = (InputSource *) lParam;
\r
8536 if (is->lineByLine) {
\r
8537 /* Feed in lines one by one */
\r
8538 char *p = is->buf;
\r
8540 while (q < is->next) {
\r
8541 if (*q++ == '\n') {
\r
8542 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8547 /* Move any partial line to the start of the buffer */
\r
8549 while (p < is->next) {
\r
8554 if (is->error != NO_ERROR || is->count == 0) {
\r
8555 /* Notify backend of the error. Note: If there was a partial
\r
8556 line at the end, it is not flushed through. */
\r
8557 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8560 /* Feed in the whole chunk of input at once */
\r
8561 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8562 is->next = is->buf;
\r
8566 /*---------------------------------------------------------------------------*\
\r
8568 * Menu enables. Used when setting various modes.
\r
8570 \*---------------------------------------------------------------------------*/
\r
8578 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8580 while (enab->item > 0) {
\r
8581 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8586 Enables gnuEnables[] = {
\r
8587 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8601 Enables icsEnables[] = {
\r
8602 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8609 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8615 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8621 Enables zippyEnables[] = {
\r
8622 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8630 Enables ncpEnables[] = {
\r
8631 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8632 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8633 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8634 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8640 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8653 Enables trainingOnEnables[] = {
\r
8654 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8665 Enables trainingOffEnables[] = {
\r
8666 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8677 /* These modify either ncpEnables or gnuEnables */
\r
8678 Enables cmailEnables[] = {
\r
8679 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8680 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8681 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8682 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8683 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8684 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8685 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8689 Enables machineThinkingEnables[] = {
\r
8690 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8691 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8692 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8693 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8694 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8695 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8696 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8697 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8698 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8699 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8700 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8701 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8702 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8703 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8704 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8708 Enables userThinkingEnables[] = {
\r
8709 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8710 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8711 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8712 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8713 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8714 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8715 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8716 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8717 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8718 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8719 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8720 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8721 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8722 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8723 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8727 /*---------------------------------------------------------------------------*\
\r
8729 * Front-end interface functions exported by XBoard.
\r
8730 * Functions appear in same order as prototypes in frontend.h.
\r
8732 \*---------------------------------------------------------------------------*/
\r
8736 static UINT prevChecked = 0;
\r
8737 static int prevPausing = 0;
\r
8740 if (pausing != prevPausing) {
\r
8741 prevPausing = pausing;
\r
8742 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8743 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8744 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8747 switch (gameMode) {
\r
8748 case BeginningOfGame:
\r
8749 if (appData.icsActive)
\r
8750 nowChecked = IDM_IcsClient;
\r
8751 else if (appData.noChessProgram)
\r
8752 nowChecked = IDM_EditGame;
\r
8754 nowChecked = IDM_MachineBlack;
\r
8756 case MachinePlaysBlack:
\r
8757 nowChecked = IDM_MachineBlack;
\r
8759 case MachinePlaysWhite:
\r
8760 nowChecked = IDM_MachineWhite;
\r
8762 case TwoMachinesPlay:
\r
8763 nowChecked = IDM_TwoMachines;
\r
8766 nowChecked = IDM_AnalysisMode;
\r
8769 nowChecked = IDM_AnalyzeFile;
\r
8772 nowChecked = IDM_EditGame;
\r
8774 case PlayFromGameFile:
\r
8775 nowChecked = IDM_LoadGame;
\r
8777 case EditPosition:
\r
8778 nowChecked = IDM_EditPosition;
\r
8781 nowChecked = IDM_Training;
\r
8783 case IcsPlayingWhite:
\r
8784 case IcsPlayingBlack:
\r
8785 case IcsObserving:
\r
8787 nowChecked = IDM_IcsClient;
\r
8794 if (prevChecked != 0)
\r
8795 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8796 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8797 if (nowChecked != 0)
\r
8798 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8799 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8801 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8802 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8803 MF_BYCOMMAND|MF_ENABLED);
\r
8805 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8806 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8809 prevChecked = nowChecked;
\r
8811 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8812 if (appData.icsActive) {
\r
8813 if (appData.icsEngineAnalyze) {
\r
8814 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8815 MF_BYCOMMAND|MF_CHECKED);
\r
8817 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8818 MF_BYCOMMAND|MF_UNCHECKED);
\r
8826 HMENU hmenu = GetMenu(hwndMain);
\r
8827 SetMenuEnables(hmenu, icsEnables);
\r
8828 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8829 MF_BYPOSITION|MF_ENABLED);
\r
8831 if (appData.zippyPlay) {
\r
8832 SetMenuEnables(hmenu, zippyEnables);
\r
8833 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8834 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8835 MF_BYCOMMAND|MF_ENABLED);
\r
8843 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8849 HMENU hmenu = GetMenu(hwndMain);
\r
8850 SetMenuEnables(hmenu, ncpEnables);
\r
8851 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8852 MF_BYPOSITION|MF_GRAYED);
\r
8853 DrawMenuBar(hwndMain);
\r
8859 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8863 SetTrainingModeOn()
\r
8866 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8867 for (i = 0; i < N_BUTTONS; i++) {
\r
8868 if (buttonDesc[i].hwnd != NULL)
\r
8869 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8874 VOID SetTrainingModeOff()
\r
8877 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8878 for (i = 0; i < N_BUTTONS; i++) {
\r
8879 if (buttonDesc[i].hwnd != NULL)
\r
8880 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8886 SetUserThinkingEnables()
\r
8888 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8892 SetMachineThinkingEnables()
\r
8894 HMENU hMenu = GetMenu(hwndMain);
\r
8895 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8897 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8899 if (gameMode == MachinePlaysBlack) {
\r
8900 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8901 } else if (gameMode == MachinePlaysWhite) {
\r
8902 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8903 } else if (gameMode == TwoMachinesPlay) {
\r
8904 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8910 DisplayTitle(char *str)
\r
8912 char title[MSG_SIZ], *host;
\r
8913 if (str[0] != NULLCHAR) {
\r
8914 strcpy(title, str);
\r
8915 } else if (appData.icsActive) {
\r
8916 if (appData.icsCommPort[0] != NULLCHAR)
\r
8919 host = appData.icsHost;
\r
8920 sprintf(title, "%s: %s", szTitle, host);
\r
8921 } else if (appData.noChessProgram) {
\r
8922 strcpy(title, szTitle);
\r
8924 strcpy(title, szTitle);
\r
8925 strcat(title, ": ");
\r
8926 strcat(title, first.tidy);
\r
8928 SetWindowText(hwndMain, title);
\r
8933 DisplayMessage(char *str1, char *str2)
\r
8937 int remain = MESSAGE_TEXT_MAX - 1;
\r
8940 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8941 messageText[0] = NULLCHAR;
\r
8943 len = strlen(str1);
\r
8944 if (len > remain) len = remain;
\r
8945 strncpy(messageText, str1, len);
\r
8946 messageText[len] = NULLCHAR;
\r
8949 if (*str2 && remain >= 2) {
\r
8951 strcat(messageText, " ");
\r
8954 len = strlen(str2);
\r
8955 if (len > remain) len = remain;
\r
8956 strncat(messageText, str2, len);
\r
8958 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8960 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8964 hdc = GetDC(hwndMain);
\r
8965 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8966 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8967 &messageRect, messageText, strlen(messageText), NULL);
\r
8968 (void) SelectObject(hdc, oldFont);
\r
8969 (void) ReleaseDC(hwndMain, hdc);
\r
8973 DisplayError(char *str, int error)
\r
8975 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8981 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8982 NULL, error, LANG_NEUTRAL,
\r
8983 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8985 sprintf(buf, "%s:\n%s", str, buf2);
\r
8987 ErrorMap *em = errmap;
\r
8988 while (em->err != 0 && em->err != error) em++;
\r
8989 if (em->err != 0) {
\r
8990 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8992 sprintf(buf, "%s:\nError code %d", str, error);
\r
8997 ErrorPopUp("Error", buf);
\r
9002 DisplayMoveError(char *str)
\r
9004 fromX = fromY = -1;
\r
9005 ClearHighlights();
\r
9006 DrawPosition(FALSE, NULL);
\r
9007 if (appData.popupMoveErrors) {
\r
9008 ErrorPopUp("Error", str);
\r
9010 DisplayMessage(str, "");
\r
9011 moveErrorMessageUp = TRUE;
\r
9016 DisplayFatalError(char *str, int error, int exitStatus)
\r
9018 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9020 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9023 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9024 NULL, error, LANG_NEUTRAL,
\r
9025 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9027 sprintf(buf, "%s:\n%s", str, buf2);
\r
9029 ErrorMap *em = errmap;
\r
9030 while (em->err != 0 && em->err != error) em++;
\r
9031 if (em->err != 0) {
\r
9032 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9034 sprintf(buf, "%s:\nError code %d", str, error);
\r
9039 if (appData.debugMode) {
\r
9040 fprintf(debugFP, "%s: %s\n", label, str);
\r
9042 if (appData.popupExitMessage) {
\r
9043 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9044 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9046 ExitEvent(exitStatus);
\r
9051 DisplayInformation(char *str)
\r
9053 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9058 DisplayNote(char *str)
\r
9060 ErrorPopUp("Note", str);
\r
9065 char *title, *question, *replyPrefix;
\r
9070 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9072 static QuestionParams *qp;
\r
9073 char reply[MSG_SIZ];
\r
9076 switch (message) {
\r
9077 case WM_INITDIALOG:
\r
9078 qp = (QuestionParams *) lParam;
\r
9079 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9080 SetWindowText(hDlg, qp->title);
\r
9081 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9082 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9086 switch (LOWORD(wParam)) {
\r
9088 strcpy(reply, qp->replyPrefix);
\r
9089 if (*reply) strcat(reply, " ");
\r
9090 len = strlen(reply);
\r
9091 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9092 strcat(reply, "\n");
\r
9093 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9094 EndDialog(hDlg, TRUE);
\r
9095 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9098 EndDialog(hDlg, FALSE);
\r
9109 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9111 QuestionParams qp;
\r
9115 qp.question = question;
\r
9116 qp.replyPrefix = replyPrefix;
\r
9118 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9119 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9120 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9121 FreeProcInstance(lpProc);
\r
9124 /* [AS] Pick FRC position */
\r
9125 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9127 static int * lpIndexFRC;
\r
9133 case WM_INITDIALOG:
\r
9134 lpIndexFRC = (int *) lParam;
\r
9136 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9138 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9139 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9140 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9141 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9146 switch( LOWORD(wParam) ) {
\r
9148 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9149 EndDialog( hDlg, 0 );
\r
9150 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9153 EndDialog( hDlg, 1 );
\r
9155 case IDC_NFG_Edit:
\r
9156 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9157 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9159 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9162 case IDC_NFG_Random:
\r
9163 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9164 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9177 int index = appData.defaultFrcPosition;
\r
9178 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9180 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9182 if( result == 0 ) {
\r
9183 appData.defaultFrcPosition = index;
\r
9189 /* [AS] Game list options */
\r
9195 static GLT_Item GLT_ItemInfo[] = {
\r
9196 { GLT_EVENT, "Event" },
\r
9197 { GLT_SITE, "Site" },
\r
9198 { GLT_DATE, "Date" },
\r
9199 { GLT_ROUND, "Round" },
\r
9200 { GLT_PLAYERS, "Players" },
\r
9201 { GLT_RESULT, "Result" },
\r
9202 { GLT_WHITE_ELO, "White Rating" },
\r
9203 { GLT_BLACK_ELO, "Black Rating" },
\r
9204 { GLT_TIME_CONTROL,"Time Control" },
\r
9205 { GLT_VARIANT, "Variant" },
\r
9206 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9207 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9211 const char * GLT_FindItem( char id )
\r
9213 const char * result = 0;
\r
9215 GLT_Item * list = GLT_ItemInfo;
\r
9217 while( list->id != 0 ) {
\r
9218 if( list->id == id ) {
\r
9219 result = list->name;
\r
9229 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9231 const char * name = GLT_FindItem( id );
\r
9234 if( index >= 0 ) {
\r
9235 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9238 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9243 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9247 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9250 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9254 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9256 pc = GLT_ALL_TAGS;
\r
9259 if( strchr( tags, *pc ) == 0 ) {
\r
9260 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9265 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9268 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9270 char result = '\0';
\r
9273 GLT_Item * list = GLT_ItemInfo;
\r
9275 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9276 while( list->id != 0 ) {
\r
9277 if( strcmp( list->name, name ) == 0 ) {
\r
9278 result = list->id;
\r
9289 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9291 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9292 int idx2 = idx1 + delta;
\r
9293 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9295 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9298 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9299 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9300 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9301 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9305 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9307 static char glt[64];
\r
9308 static char * lpUserGLT;
\r
9312 case WM_INITDIALOG:
\r
9313 lpUserGLT = (char *) lParam;
\r
9315 strcpy( glt, lpUserGLT );
\r
9317 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9319 /* Initialize list */
\r
9320 GLT_TagsToList( hDlg, glt );
\r
9322 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9327 switch( LOWORD(wParam) ) {
\r
9330 char * pc = lpUserGLT;
\r
9332 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9336 id = GLT_ListItemToTag( hDlg, idx );
\r
9340 } while( id != '\0' );
\r
9342 EndDialog( hDlg, 0 );
\r
9345 EndDialog( hDlg, 1 );
\r
9348 case IDC_GLT_Default:
\r
9349 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9350 GLT_TagsToList( hDlg, glt );
\r
9353 case IDC_GLT_Restore:
\r
9354 strcpy( glt, lpUserGLT );
\r
9355 GLT_TagsToList( hDlg, glt );
\r
9359 GLT_MoveSelection( hDlg, -1 );
\r
9362 case IDC_GLT_Down:
\r
9363 GLT_MoveSelection( hDlg, +1 );
\r
9373 int GameListOptions()
\r
9377 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9379 strcpy( glt, appData.gameListTags );
\r
9381 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9383 if( result == 0 ) {
\r
9384 /* [AS] Memory leak here! */
\r
9385 appData.gameListTags = strdup( glt );
\r
9393 DisplayIcsInteractionTitle(char *str)
\r
9395 char consoleTitle[MSG_SIZ];
\r
9397 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9398 SetWindowText(hwndConsole, consoleTitle);
\r
9402 DrawPosition(int fullRedraw, Board board)
\r
9404 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9407 void NotifyFrontendLogin()
\r
9410 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9416 fromX = fromY = -1;
\r
9417 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9418 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9419 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9420 dragInfo.lastpos = dragInfo.pos;
\r
9421 dragInfo.start.x = dragInfo.start.y = -1;
\r
9422 dragInfo.from = dragInfo.start;
\r
9424 DrawPosition(TRUE, NULL);
\r
9430 CommentPopUp(char *title, char *str)
\r
9432 HWND hwnd = GetActiveWindow();
\r
9433 EitherCommentPopUp(0, title, str, FALSE);
\r
9435 SetActiveWindow(hwnd);
\r
9439 CommentPopDown(void)
\r
9441 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9442 if (commentDialog) {
\r
9443 ShowWindow(commentDialog, SW_HIDE);
\r
9445 commentUp = FALSE;
\r
9449 EditCommentPopUp(int index, char *title, char *str)
\r
9451 EitherCommentPopUp(index, title, str, TRUE);
\r
9458 MyPlaySound(&sounds[(int)SoundMove]);
\r
9461 VOID PlayIcsWinSound()
\r
9463 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9466 VOID PlayIcsLossSound()
\r
9468 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9471 VOID PlayIcsDrawSound()
\r
9473 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9476 VOID PlayIcsUnfinishedSound()
\r
9478 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9484 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9492 consoleEcho = TRUE;
\r
9493 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9494 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9495 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9504 consoleEcho = FALSE;
\r
9505 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9506 /* This works OK: set text and background both to the same color */
\r
9508 cf.crTextColor = COLOR_ECHOOFF;
\r
9509 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9510 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9513 /* No Raw()...? */
\r
9515 void Colorize(ColorClass cc, int continuation)
\r
9517 currentColorClass = cc;
\r
9518 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9519 consoleCF.crTextColor = textAttribs[cc].color;
\r
9520 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9521 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9527 static char buf[MSG_SIZ];
\r
9528 DWORD bufsiz = MSG_SIZ;
\r
9530 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9531 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9533 if (!GetUserName(buf, &bufsiz)) {
\r
9534 /*DisplayError("Error getting user name", GetLastError());*/
\r
9535 strcpy(buf, "User");
\r
9543 static char buf[MSG_SIZ];
\r
9544 DWORD bufsiz = MSG_SIZ;
\r
9546 if (!GetComputerName(buf, &bufsiz)) {
\r
9547 /*DisplayError("Error getting host name", GetLastError());*/
\r
9548 strcpy(buf, "Unknown");
\r
9555 ClockTimerRunning()
\r
9557 return clockTimerEvent != 0;
\r
9563 if (clockTimerEvent == 0) return FALSE;
\r
9564 KillTimer(hwndMain, clockTimerEvent);
\r
9565 clockTimerEvent = 0;
\r
9570 StartClockTimer(long millisec)
\r
9572 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9573 (UINT) millisec, NULL);
\r
9577 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9580 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9582 if(appData.noGUI) return;
\r
9583 hdc = GetDC(hwndMain);
\r
9584 if (!IsIconic(hwndMain)) {
\r
9585 DisplayAClock(hdc, timeRemaining, highlight,
\r
9586 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9588 if (highlight && iconCurrent == iconBlack) {
\r
9589 iconCurrent = iconWhite;
\r
9590 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9591 if (IsIconic(hwndMain)) {
\r
9592 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9595 (void) ReleaseDC(hwndMain, hdc);
\r
9597 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9601 DisplayBlackClock(long timeRemaining, int highlight)
\r
9604 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9606 if(appData.noGUI) return;
\r
9607 hdc = GetDC(hwndMain);
\r
9608 if (!IsIconic(hwndMain)) {
\r
9609 DisplayAClock(hdc, timeRemaining, highlight,
\r
9610 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9612 if (highlight && iconCurrent == iconWhite) {
\r
9613 iconCurrent = iconBlack;
\r
9614 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9615 if (IsIconic(hwndMain)) {
\r
9616 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9619 (void) ReleaseDC(hwndMain, hdc);
\r
9621 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9626 LoadGameTimerRunning()
\r
9628 return loadGameTimerEvent != 0;
\r
9632 StopLoadGameTimer()
\r
9634 if (loadGameTimerEvent == 0) return FALSE;
\r
9635 KillTimer(hwndMain, loadGameTimerEvent);
\r
9636 loadGameTimerEvent = 0;
\r
9641 StartLoadGameTimer(long millisec)
\r
9643 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9644 (UINT) millisec, NULL);
\r
9652 char fileTitle[MSG_SIZ];
\r
9654 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9655 f = OpenFileDialog(hwndMain, "a", defName,
\r
9656 appData.oldSaveStyle ? "gam" : "pgn",
\r
9658 "Save Game to File", NULL, fileTitle, NULL);
\r
9660 SaveGame(f, 0, "");
\r
9667 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9669 if (delayedTimerEvent != 0) {
\r
9670 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9671 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9673 KillTimer(hwndMain, delayedTimerEvent);
\r
9674 delayedTimerEvent = 0;
\r
9675 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9676 delayedTimerCallback();
\r
9678 delayedTimerCallback = cb;
\r
9679 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9680 (UINT) millisec, NULL);
\r
9683 DelayedEventCallback
\r
9686 if (delayedTimerEvent) {
\r
9687 return delayedTimerCallback;
\r
9694 CancelDelayedEvent()
\r
9696 if (delayedTimerEvent) {
\r
9697 KillTimer(hwndMain, delayedTimerEvent);
\r
9698 delayedTimerEvent = 0;
\r
9702 DWORD GetWin32Priority(int nice)
\r
9703 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9705 REALTIME_PRIORITY_CLASS 0x00000100
\r
9706 HIGH_PRIORITY_CLASS 0x00000080
\r
9707 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9708 NORMAL_PRIORITY_CLASS 0x00000020
\r
9709 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9710 IDLE_PRIORITY_CLASS 0x00000040
\r
9712 if (nice < -15) return 0x00000080;
\r
9713 if (nice < 0) return 0x00008000;
\r
9714 if (nice == 0) return 0x00000020;
\r
9715 if (nice < 15) return 0x00004000;
\r
9716 return 0x00000040;
\r
9719 /* Start a child process running the given program.
\r
9720 The process's standard output can be read from "from", and its
\r
9721 standard input can be written to "to".
\r
9722 Exit with fatal error if anything goes wrong.
\r
9723 Returns an opaque pointer that can be used to destroy the process
\r
9727 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9729 #define BUFSIZE 4096
\r
9731 HANDLE hChildStdinRd, hChildStdinWr,
\r
9732 hChildStdoutRd, hChildStdoutWr;
\r
9733 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9734 SECURITY_ATTRIBUTES saAttr;
\r
9736 PROCESS_INFORMATION piProcInfo;
\r
9737 STARTUPINFO siStartInfo;
\r
9739 char buf[MSG_SIZ];
\r
9742 if (appData.debugMode) {
\r
9743 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9748 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9749 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9750 saAttr.bInheritHandle = TRUE;
\r
9751 saAttr.lpSecurityDescriptor = NULL;
\r
9754 * The steps for redirecting child's STDOUT:
\r
9755 * 1. Create anonymous pipe to be STDOUT for child.
\r
9756 * 2. Create a noninheritable duplicate of read handle,
\r
9757 * and close the inheritable read handle.
\r
9760 /* Create a pipe for the child's STDOUT. */
\r
9761 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9762 return GetLastError();
\r
9765 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9766 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9767 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9768 FALSE, /* not inherited */
\r
9769 DUPLICATE_SAME_ACCESS);
\r
9771 return GetLastError();
\r
9773 CloseHandle(hChildStdoutRd);
\r
9776 * The steps for redirecting child's STDIN:
\r
9777 * 1. Create anonymous pipe to be STDIN for child.
\r
9778 * 2. Create a noninheritable duplicate of write handle,
\r
9779 * and close the inheritable write handle.
\r
9782 /* Create a pipe for the child's STDIN. */
\r
9783 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9784 return GetLastError();
\r
9787 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9788 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9789 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9790 FALSE, /* not inherited */
\r
9791 DUPLICATE_SAME_ACCESS);
\r
9793 return GetLastError();
\r
9795 CloseHandle(hChildStdinWr);
\r
9797 /* Arrange to (1) look in dir for the child .exe file, and
\r
9798 * (2) have dir be the child's working directory. Interpret
\r
9799 * dir relative to the directory WinBoard loaded from. */
\r
9800 GetCurrentDirectory(MSG_SIZ, buf);
\r
9801 SetCurrentDirectory(installDir);
\r
9802 SetCurrentDirectory(dir);
\r
9804 /* Now create the child process. */
\r
9806 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9807 siStartInfo.lpReserved = NULL;
\r
9808 siStartInfo.lpDesktop = NULL;
\r
9809 siStartInfo.lpTitle = NULL;
\r
9810 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9811 siStartInfo.cbReserved2 = 0;
\r
9812 siStartInfo.lpReserved2 = NULL;
\r
9813 siStartInfo.hStdInput = hChildStdinRd;
\r
9814 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9815 siStartInfo.hStdError = hChildStdoutWr;
\r
9817 fSuccess = CreateProcess(NULL,
\r
9818 cmdLine, /* command line */
\r
9819 NULL, /* process security attributes */
\r
9820 NULL, /* primary thread security attrs */
\r
9821 TRUE, /* handles are inherited */
\r
9822 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9823 NULL, /* use parent's environment */
\r
9825 &siStartInfo, /* STARTUPINFO pointer */
\r
9826 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9828 err = GetLastError();
\r
9829 SetCurrentDirectory(buf); /* return to prev directory */
\r
9834 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9835 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9836 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9839 /* Close the handles we don't need in the parent */
\r
9840 CloseHandle(piProcInfo.hThread);
\r
9841 CloseHandle(hChildStdinRd);
\r
9842 CloseHandle(hChildStdoutWr);
\r
9844 /* Prepare return value */
\r
9845 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9846 cp->kind = CPReal;
\r
9847 cp->hProcess = piProcInfo.hProcess;
\r
9848 cp->pid = piProcInfo.dwProcessId;
\r
9849 cp->hFrom = hChildStdoutRdDup;
\r
9850 cp->hTo = hChildStdinWrDup;
\r
9852 *pr = (void *) cp;
\r
9854 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9855 2000 where engines sometimes don't see the initial command(s)
\r
9856 from WinBoard and hang. I don't understand how that can happen,
\r
9857 but the Sleep is harmless, so I've put it in. Others have also
\r
9858 reported what may be the same problem, so hopefully this will fix
\r
9859 it for them too. */
\r
9867 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9869 ChildProc *cp; int result;
\r
9871 cp = (ChildProc *) pr;
\r
9872 if (cp == NULL) return;
\r
9874 switch (cp->kind) {
\r
9876 /* TerminateProcess is considered harmful, so... */
\r
9877 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9878 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9879 /* The following doesn't work because the chess program
\r
9880 doesn't "have the same console" as WinBoard. Maybe
\r
9881 we could arrange for this even though neither WinBoard
\r
9882 nor the chess program uses a console for stdio? */
\r
9883 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9885 /* [AS] Special termination modes for misbehaving programs... */
\r
9886 if( signal == 9 ) {
\r
9887 result = TerminateProcess( cp->hProcess, 0 );
\r
9889 if ( appData.debugMode) {
\r
9890 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9893 else if( signal == 10 ) {
\r
9894 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9896 if( dw != WAIT_OBJECT_0 ) {
\r
9897 result = TerminateProcess( cp->hProcess, 0 );
\r
9899 if ( appData.debugMode) {
\r
9900 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9906 CloseHandle(cp->hProcess);
\r
9910 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9914 closesocket(cp->sock);
\r
9919 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9920 closesocket(cp->sock);
\r
9921 closesocket(cp->sock2);
\r
9929 InterruptChildProcess(ProcRef pr)
\r
9933 cp = (ChildProc *) pr;
\r
9934 if (cp == NULL) return;
\r
9935 switch (cp->kind) {
\r
9937 /* The following doesn't work because the chess program
\r
9938 doesn't "have the same console" as WinBoard. Maybe
\r
9939 we could arrange for this even though neither WinBoard
\r
9940 nor the chess program uses a console for stdio */
\r
9941 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9946 /* Can't interrupt */
\r
9950 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9957 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9959 char cmdLine[MSG_SIZ];
\r
9961 if (port[0] == NULLCHAR) {
\r
9962 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9964 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9966 return StartChildProcess(cmdLine, "", pr);
\r
9970 /* Code to open TCP sockets */
\r
9973 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9978 struct sockaddr_in sa, mysa;
\r
9979 struct hostent FAR *hp;
\r
9980 unsigned short uport;
\r
9981 WORD wVersionRequested;
\r
9984 /* Initialize socket DLL */
\r
9985 wVersionRequested = MAKEWORD(1, 1);
\r
9986 err = WSAStartup(wVersionRequested, &wsaData);
\r
9987 if (err != 0) return err;
\r
9990 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9991 err = WSAGetLastError();
\r
9996 /* Bind local address using (mostly) don't-care values.
\r
9998 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9999 mysa.sin_family = AF_INET;
\r
10000 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10001 uport = (unsigned short) 0;
\r
10002 mysa.sin_port = htons(uport);
\r
10003 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10004 == SOCKET_ERROR) {
\r
10005 err = WSAGetLastError();
\r
10010 /* Resolve remote host name */
\r
10011 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10012 if (!(hp = gethostbyname(host))) {
\r
10013 unsigned int b0, b1, b2, b3;
\r
10015 err = WSAGetLastError();
\r
10017 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10018 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10019 hp->h_addrtype = AF_INET;
\r
10020 hp->h_length = 4;
\r
10021 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10022 hp->h_addr_list[0] = (char *) malloc(4);
\r
10023 hp->h_addr_list[0][0] = (char) b0;
\r
10024 hp->h_addr_list[0][1] = (char) b1;
\r
10025 hp->h_addr_list[0][2] = (char) b2;
\r
10026 hp->h_addr_list[0][3] = (char) b3;
\r
10032 sa.sin_family = hp->h_addrtype;
\r
10033 uport = (unsigned short) atoi(port);
\r
10034 sa.sin_port = htons(uport);
\r
10035 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10037 /* Make connection */
\r
10038 if (connect(s, (struct sockaddr *) &sa,
\r
10039 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10040 err = WSAGetLastError();
\r
10045 /* Prepare return value */
\r
10046 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10047 cp->kind = CPSock;
\r
10049 *pr = (ProcRef *) cp;
\r
10055 OpenCommPort(char *name, ProcRef *pr)
\r
10060 char fullname[MSG_SIZ];
\r
10062 if (*name != '\\')
\r
10063 sprintf(fullname, "\\\\.\\%s", name);
\r
10065 strcpy(fullname, name);
\r
10067 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10068 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10069 if (h == (HANDLE) -1) {
\r
10070 return GetLastError();
\r
10074 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10076 /* Accumulate characters until a 100ms pause, then parse */
\r
10077 ct.ReadIntervalTimeout = 100;
\r
10078 ct.ReadTotalTimeoutMultiplier = 0;
\r
10079 ct.ReadTotalTimeoutConstant = 0;
\r
10080 ct.WriteTotalTimeoutMultiplier = 0;
\r
10081 ct.WriteTotalTimeoutConstant = 0;
\r
10082 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10084 /* Prepare return value */
\r
10085 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10086 cp->kind = CPComm;
\r
10089 *pr = (ProcRef *) cp;
\r
10095 OpenLoopback(ProcRef *pr)
\r
10097 DisplayFatalError("Not implemented", 0, 1);
\r
10103 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10107 SOCKET s, s2, s3;
\r
10108 struct sockaddr_in sa, mysa;
\r
10109 struct hostent FAR *hp;
\r
10110 unsigned short uport;
\r
10111 WORD wVersionRequested;
\r
10114 char stderrPortStr[MSG_SIZ];
\r
10116 /* Initialize socket DLL */
\r
10117 wVersionRequested = MAKEWORD(1, 1);
\r
10118 err = WSAStartup(wVersionRequested, &wsaData);
\r
10119 if (err != 0) return err;
\r
10121 /* Resolve remote host name */
\r
10122 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10123 if (!(hp = gethostbyname(host))) {
\r
10124 unsigned int b0, b1, b2, b3;
\r
10126 err = WSAGetLastError();
\r
10128 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10129 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10130 hp->h_addrtype = AF_INET;
\r
10131 hp->h_length = 4;
\r
10132 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10133 hp->h_addr_list[0] = (char *) malloc(4);
\r
10134 hp->h_addr_list[0][0] = (char) b0;
\r
10135 hp->h_addr_list[0][1] = (char) b1;
\r
10136 hp->h_addr_list[0][2] = (char) b2;
\r
10137 hp->h_addr_list[0][3] = (char) b3;
\r
10143 sa.sin_family = hp->h_addrtype;
\r
10144 uport = (unsigned short) 514;
\r
10145 sa.sin_port = htons(uport);
\r
10146 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10148 /* Bind local socket to unused "privileged" port address
\r
10150 s = INVALID_SOCKET;
\r
10151 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10152 mysa.sin_family = AF_INET;
\r
10153 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10154 for (fromPort = 1023;; fromPort--) {
\r
10155 if (fromPort < 0) {
\r
10157 return WSAEADDRINUSE;
\r
10159 if (s == INVALID_SOCKET) {
\r
10160 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10161 err = WSAGetLastError();
\r
10166 uport = (unsigned short) fromPort;
\r
10167 mysa.sin_port = htons(uport);
\r
10168 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10169 == SOCKET_ERROR) {
\r
10170 err = WSAGetLastError();
\r
10171 if (err == WSAEADDRINUSE) continue;
\r
10175 if (connect(s, (struct sockaddr *) &sa,
\r
10176 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10177 err = WSAGetLastError();
\r
10178 if (err == WSAEADDRINUSE) {
\r
10189 /* Bind stderr local socket to unused "privileged" port address
\r
10191 s2 = INVALID_SOCKET;
\r
10192 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10193 mysa.sin_family = AF_INET;
\r
10194 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10195 for (fromPort = 1023;; fromPort--) {
\r
10196 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10197 if (fromPort < 0) {
\r
10198 (void) closesocket(s);
\r
10200 return WSAEADDRINUSE;
\r
10202 if (s2 == INVALID_SOCKET) {
\r
10203 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10204 err = WSAGetLastError();
\r
10210 uport = (unsigned short) fromPort;
\r
10211 mysa.sin_port = htons(uport);
\r
10212 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10213 == SOCKET_ERROR) {
\r
10214 err = WSAGetLastError();
\r
10215 if (err == WSAEADDRINUSE) continue;
\r
10216 (void) closesocket(s);
\r
10220 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10221 err = WSAGetLastError();
\r
10222 if (err == WSAEADDRINUSE) {
\r
10224 s2 = INVALID_SOCKET;
\r
10227 (void) closesocket(s);
\r
10228 (void) closesocket(s2);
\r
10234 prevStderrPort = fromPort; // remember port used
\r
10235 sprintf(stderrPortStr, "%d", fromPort);
\r
10237 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10238 err = WSAGetLastError();
\r
10239 (void) closesocket(s);
\r
10240 (void) closesocket(s2);
\r
10245 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10246 err = WSAGetLastError();
\r
10247 (void) closesocket(s);
\r
10248 (void) closesocket(s2);
\r
10252 if (*user == NULLCHAR) user = UserName();
\r
10253 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10254 err = WSAGetLastError();
\r
10255 (void) closesocket(s);
\r
10256 (void) closesocket(s2);
\r
10260 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10261 err = WSAGetLastError();
\r
10262 (void) closesocket(s);
\r
10263 (void) closesocket(s2);
\r
10268 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10269 err = WSAGetLastError();
\r
10270 (void) closesocket(s);
\r
10271 (void) closesocket(s2);
\r
10275 (void) closesocket(s2); /* Stop listening */
\r
10277 /* Prepare return value */
\r
10278 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10279 cp->kind = CPRcmd;
\r
10282 *pr = (ProcRef *) cp;
\r
10289 AddInputSource(ProcRef pr, int lineByLine,
\r
10290 InputCallback func, VOIDSTAR closure)
\r
10292 InputSource *is, *is2 = NULL;
\r
10293 ChildProc *cp = (ChildProc *) pr;
\r
10295 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10296 is->lineByLine = lineByLine;
\r
10298 is->closure = closure;
\r
10299 is->second = NULL;
\r
10300 is->next = is->buf;
\r
10301 if (pr == NoProc) {
\r
10302 is->kind = CPReal;
\r
10303 consoleInputSource = is;
\r
10305 is->kind = cp->kind;
\r
10307 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10308 we create all threads suspended so that the is->hThread variable can be
\r
10309 safely assigned, then let the threads start with ResumeThread.
\r
10311 switch (cp->kind) {
\r
10313 is->hFile = cp->hFrom;
\r
10314 cp->hFrom = NULL; /* now owned by InputThread */
\r
10316 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10317 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10321 is->hFile = cp->hFrom;
\r
10322 cp->hFrom = NULL; /* now owned by InputThread */
\r
10324 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10325 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10329 is->sock = cp->sock;
\r
10331 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10332 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10336 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10338 is->sock = cp->sock;
\r
10339 is->second = is2;
\r
10340 is2->sock = cp->sock2;
\r
10341 is2->second = is2;
\r
10343 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10344 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10346 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10347 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10351 if( is->hThread != NULL ) {
\r
10352 ResumeThread( is->hThread );
\r
10355 if( is2 != NULL && is2->hThread != NULL ) {
\r
10356 ResumeThread( is2->hThread );
\r
10360 return (InputSourceRef) is;
\r
10364 RemoveInputSource(InputSourceRef isr)
\r
10368 is = (InputSource *) isr;
\r
10369 is->hThread = NULL; /* tell thread to stop */
\r
10370 CloseHandle(is->hThread);
\r
10371 if (is->second != NULL) {
\r
10372 is->second->hThread = NULL;
\r
10373 CloseHandle(is->second->hThread);
\r
10377 int no_wrap(char *message, int count)
\r
10379 ConsoleOutput(message, count, FALSE);
\r
10384 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10387 int outCount = SOCKET_ERROR;
\r
10388 ChildProc *cp = (ChildProc *) pr;
\r
10389 static OVERLAPPED ovl;
\r
10390 static int line = 0;
\r
10392 if (pr == NoProc)
\r
10394 if (appData.noJoin || !appData.useInternalWrap)
\r
10395 return no_wrap(message, count);
\r
10398 int width = get_term_width();
\r
10399 int len = wrap(NULL, message, count, width, &line);
\r
10400 char *msg = malloc(len);
\r
10404 return no_wrap(message, count);
\r
10407 dbgchk = wrap(msg, message, count, width, &line);
\r
10408 if (dbgchk != len && appData.debugMode)
\r
10409 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10410 ConsoleOutput(msg, len, FALSE);
\r
10417 if (ovl.hEvent == NULL) {
\r
10418 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10420 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10422 switch (cp->kind) {
\r
10425 outCount = send(cp->sock, message, count, 0);
\r
10426 if (outCount == SOCKET_ERROR) {
\r
10427 *outError = WSAGetLastError();
\r
10429 *outError = NO_ERROR;
\r
10434 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10435 &dOutCount, NULL)) {
\r
10436 *outError = NO_ERROR;
\r
10437 outCount = (int) dOutCount;
\r
10439 *outError = GetLastError();
\r
10444 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10445 &dOutCount, &ovl);
\r
10446 if (*outError == NO_ERROR) {
\r
10447 outCount = (int) dOutCount;
\r
10455 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10458 /* Ignore delay, not implemented for WinBoard */
\r
10459 return OutputToProcess(pr, message, count, outError);
\r
10464 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10465 char *buf, int count, int error)
\r
10467 DisplayFatalError("Not implemented", 0, 1);
\r
10470 /* see wgamelist.c for Game List functions */
\r
10471 /* see wedittags.c for Edit Tags functions */
\r
10478 char buf[MSG_SIZ];
\r
10481 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10482 f = fopen(buf, "r");
\r
10484 ProcessICSInitScript(f);
\r
10492 StartAnalysisClock()
\r
10494 if (analysisTimerEvent) return;
\r
10495 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10496 (UINT) 2000, NULL);
\r
10500 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10502 static HANDLE hwndText;
\r
10504 static int sizeX, sizeY;
\r
10505 int newSizeX, newSizeY, flags;
\r
10508 switch (message) {
\r
10509 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10510 /* Initialize the dialog items */
\r
10511 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10512 SetWindowText(hDlg, analysisTitle);
\r
10513 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10514 /* Size and position the dialog */
\r
10515 if (!analysisDialog) {
\r
10516 analysisDialog = hDlg;
\r
10517 flags = SWP_NOZORDER;
\r
10518 GetClientRect(hDlg, &rect);
\r
10519 sizeX = rect.right;
\r
10520 sizeY = rect.bottom;
\r
10521 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10522 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10523 WINDOWPLACEMENT wp;
\r
10524 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10525 wp.length = sizeof(WINDOWPLACEMENT);
\r
10527 wp.showCmd = SW_SHOW;
\r
10528 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10529 wp.rcNormalPosition.left = analysisX;
\r
10530 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10531 wp.rcNormalPosition.top = analysisY;
\r
10532 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10533 SetWindowPlacement(hDlg, &wp);
\r
10535 GetClientRect(hDlg, &rect);
\r
10536 newSizeX = rect.right;
\r
10537 newSizeY = rect.bottom;
\r
10538 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10539 newSizeX, newSizeY);
\r
10540 sizeX = newSizeX;
\r
10541 sizeY = newSizeY;
\r
10546 case WM_COMMAND: /* message: received a command */
\r
10547 switch (LOWORD(wParam)) {
\r
10549 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10550 ExitAnalyzeMode();
\r
10562 newSizeX = LOWORD(lParam);
\r
10563 newSizeY = HIWORD(lParam);
\r
10564 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10565 sizeX = newSizeX;
\r
10566 sizeY = newSizeY;
\r
10569 case WM_GETMINMAXINFO:
\r
10570 /* Prevent resizing window too small */
\r
10571 mmi = (MINMAXINFO *) lParam;
\r
10572 mmi->ptMinTrackSize.x = 100;
\r
10573 mmi->ptMinTrackSize.y = 100;
\r
10580 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10582 highlightInfo.sq[0].x = fromX;
\r
10583 highlightInfo.sq[0].y = fromY;
\r
10584 highlightInfo.sq[1].x = toX;
\r
10585 highlightInfo.sq[1].y = toY;
\r
10589 ClearHighlights()
\r
10591 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10592 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10596 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10598 premoveHighlightInfo.sq[0].x = fromX;
\r
10599 premoveHighlightInfo.sq[0].y = fromY;
\r
10600 premoveHighlightInfo.sq[1].x = toX;
\r
10601 premoveHighlightInfo.sq[1].y = toY;
\r
10605 ClearPremoveHighlights()
\r
10607 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10608 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10612 ShutDownFrontEnd()
\r
10614 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10615 DeleteClipboardTempFiles();
\r
10621 if (IsIconic(hwndMain))
\r
10622 ShowWindow(hwndMain, SW_RESTORE);
\r
10624 SetActiveWindow(hwndMain);
\r
10628 * Prototypes for animation support routines
\r
10630 static void ScreenSquare(int column, int row, POINT * pt);
\r
10631 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10632 POINT frames[], int * nFrames);
\r
10636 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10637 { // [HGM] atomic: animate blast wave
\r
10639 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10640 explodeInfo.fromX = fromX;
\r
10641 explodeInfo.fromY = fromY;
\r
10642 explodeInfo.toX = toX;
\r
10643 explodeInfo.toY = toY;
\r
10644 for(i=1; i<nFrames; i++) {
\r
10645 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10646 DrawPosition(FALSE, NULL);
\r
10647 Sleep(appData.animSpeed);
\r
10649 explodeInfo.radius = 0;
\r
10650 DrawPosition(TRUE, NULL);
\r
10653 #define kFactor 4
\r
10656 AnimateMove(board, fromX, fromY, toX, toY)
\r
10663 ChessSquare piece;
\r
10664 POINT start, finish, mid;
\r
10665 POINT frames[kFactor * 2 + 1];
\r
10668 if (!appData.animate) return;
\r
10669 if (doingSizing) return;
\r
10670 if (fromY < 0 || fromX < 0) return;
\r
10671 piece = board[fromY][fromX];
\r
10672 if (piece >= EmptySquare) return;
\r
10674 ScreenSquare(fromX, fromY, &start);
\r
10675 ScreenSquare(toX, toY, &finish);
\r
10677 /* All pieces except knights move in straight line */
\r
10678 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10679 mid.x = start.x + (finish.x - start.x) / 2;
\r
10680 mid.y = start.y + (finish.y - start.y) / 2;
\r
10682 /* Knight: make diagonal movement then straight */
\r
10683 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10684 mid.x = start.x + (finish.x - start.x) / 2;
\r
10685 mid.y = finish.y;
\r
10687 mid.x = finish.x;
\r
10688 mid.y = start.y + (finish.y - start.y) / 2;
\r
10692 /* Don't use as many frames for very short moves */
\r
10693 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10694 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10696 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10698 animInfo.from.x = fromX;
\r
10699 animInfo.from.y = fromY;
\r
10700 animInfo.to.x = toX;
\r
10701 animInfo.to.y = toY;
\r
10702 animInfo.lastpos = start;
\r
10703 animInfo.piece = piece;
\r
10704 for (n = 0; n < nFrames; n++) {
\r
10705 animInfo.pos = frames[n];
\r
10706 DrawPosition(FALSE, NULL);
\r
10707 animInfo.lastpos = animInfo.pos;
\r
10708 Sleep(appData.animSpeed);
\r
10710 animInfo.pos = finish;
\r
10711 DrawPosition(FALSE, NULL);
\r
10712 animInfo.piece = EmptySquare;
\r
10713 if(gameInfo.variant == VariantAtomic &&
\r
10714 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10715 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10718 /* Convert board position to corner of screen rect and color */
\r
10721 ScreenSquare(column, row, pt)
\r
10722 int column; int row; POINT * pt;
\r
10725 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10726 pt->y = lineGap + row * (squareSize + lineGap);
\r
10728 pt->x = lineGap + column * (squareSize + lineGap);
\r
10729 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10733 /* Generate a series of frame coords from start->mid->finish.
\r
10734 The movement rate doubles until the half way point is
\r
10735 reached, then halves back down to the final destination,
\r
10736 which gives a nice slow in/out effect. The algorithmn
\r
10737 may seem to generate too many intermediates for short
\r
10738 moves, but remember that the purpose is to attract the
\r
10739 viewers attention to the piece about to be moved and
\r
10740 then to where it ends up. Too few frames would be less
\r
10744 Tween(start, mid, finish, factor, frames, nFrames)
\r
10745 POINT * start; POINT * mid;
\r
10746 POINT * finish; int factor;
\r
10747 POINT frames[]; int * nFrames;
\r
10749 int n, fraction = 1, count = 0;
\r
10751 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10752 for (n = 0; n < factor; n++)
\r
10754 for (n = 0; n < factor; n++) {
\r
10755 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10756 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10758 fraction = fraction / 2;
\r
10762 frames[count] = *mid;
\r
10765 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10767 for (n = 0; n < factor; n++) {
\r
10768 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10769 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10771 fraction = fraction * 2;
\r
10773 *nFrames = count;
\r
10777 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10779 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10781 EvalGraphSet( first, last, current, pvInfoList );
\r
10784 void SetProgramStats( FrontEndProgramStats * stats )
\r
10786 EngineOutputUpdate( stats );
\r