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 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 BOOLEAN commentDialogUp = 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 BOOLEAN 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
1396 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1397 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1398 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1399 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1400 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1401 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1402 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1403 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1404 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1405 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1406 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1407 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1408 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1409 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1410 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1411 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1412 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1413 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1414 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1415 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1416 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1417 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1418 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1419 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1420 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1421 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1422 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1423 /* [AS] Layout stuff */
\r
1424 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1425 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1426 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1427 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1428 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1430 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1431 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1432 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1433 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1434 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1436 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1437 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1438 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1439 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1440 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1442 { NULL, ArgNone, NULL, FALSE }
\r
1446 /* Kludge for indirection files on command line */
\r
1447 char* lastIndirectionFilename;
\r
1448 ArgDescriptor argDescriptorIndirection =
\r
1449 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1453 ExitArgError(char *msg, char *badArg)
\r
1455 char buf[MSG_SIZ];
\r
1457 sprintf(buf, "%s %s", msg, badArg);
\r
1458 DisplayFatalError(buf, 0, 2);
\r
1462 /* Command line font name parser. NULL name means do nothing.
\r
1463 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1464 For backward compatibility, syntax without the colon is also
\r
1465 accepted, but font names with digits in them won't work in that case.
\r
1468 ParseFontName(char *name, MyFontParams *mfp)
\r
1471 if (name == NULL) return;
\r
1473 q = strchr(p, ':');
\r
1475 if (q - p >= sizeof(mfp->faceName))
\r
1476 ExitArgError("Font name too long:", name);
\r
1477 memcpy(mfp->faceName, p, q - p);
\r
1478 mfp->faceName[q - p] = NULLCHAR;
\r
1481 q = mfp->faceName;
\r
1482 while (*p && !isdigit(*p)) {
\r
1484 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1485 ExitArgError("Font name too long:", name);
\r
1487 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1490 if (!*p) ExitArgError("Font point size missing:", name);
\r
1491 mfp->pointSize = (float) atof(p);
\r
1492 mfp->bold = (strchr(p, 'b') != NULL);
\r
1493 mfp->italic = (strchr(p, 'i') != NULL);
\r
1494 mfp->underline = (strchr(p, 'u') != NULL);
\r
1495 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1498 /* Color name parser.
\r
1499 X version accepts X color names, but this one
\r
1500 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1502 ParseColorName(char *name)
\r
1504 int red, green, blue, count;
\r
1505 char buf[MSG_SIZ];
\r
1507 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1509 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1510 &red, &green, &blue);
\r
1513 sprintf(buf, "Can't parse color name %s", name);
\r
1514 DisplayError(buf, 0);
\r
1515 return RGB(0, 0, 0);
\r
1517 return PALETTERGB(red, green, blue);
\r
1521 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1523 char *e = argValue;
\r
1527 if (*e == 'b') eff |= CFE_BOLD;
\r
1528 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1529 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1530 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1531 else if (*e == '#' || isdigit(*e)) break;
\r
1535 *color = ParseColorName(e);
\r
1540 ParseBoardSize(char *name)
\r
1542 BoardSize bs = SizeTiny;
\r
1543 while (sizeInfo[bs].name != NULL) {
\r
1544 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1547 ExitArgError("Unrecognized board size value", name);
\r
1548 return bs; /* not reached */
\r
1553 StringGet(void *getClosure)
\r
1555 char **p = (char **) getClosure;
\r
1560 FileGet(void *getClosure)
\r
1563 FILE* f = (FILE*) getClosure;
\r
1566 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1573 /* Parse settings file named "name". If file found, return the
\r
1574 full name in fullname and return TRUE; else return FALSE */
\r
1576 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1580 int ok; char buf[MSG_SIZ];
\r
1582 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1583 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1584 sprintf(buf, "%s.ini", name);
\r
1585 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1588 f = fopen(fullname, "r");
\r
1590 ParseArgs(FileGet, f);
\r
1599 ParseArgs(GetFunc get, void *cl)
\r
1601 char argName[ARG_MAX];
\r
1602 char argValue[ARG_MAX];
\r
1603 ArgDescriptor *ad;
\r
1612 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1613 if (ch == NULLCHAR) break;
\r
1615 /* Comment to end of line */
\r
1617 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1619 } else if (ch == '/' || ch == '-') {
\r
1622 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1623 ch != '\n' && ch != '\t') {
\r
1629 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1630 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1632 if (ad->argName == NULL)
\r
1633 ExitArgError("Unrecognized argument", argName);
\r
1635 } else if (ch == '@') {
\r
1636 /* Indirection file */
\r
1637 ad = &argDescriptorIndirection;
\r
1640 /* Positional argument */
\r
1641 ad = &argDescriptors[posarg++];
\r
1642 strcpy(argName, ad->argName);
\r
1645 if (ad->argType == ArgTrue) {
\r
1646 *(Boolean *) ad->argLoc = TRUE;
\r
1649 if (ad->argType == ArgFalse) {
\r
1650 *(Boolean *) ad->argLoc = FALSE;
\r
1654 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1655 if (ch == NULLCHAR || ch == '\n') {
\r
1656 ExitArgError("No value provided for argument", argName);
\r
1660 // Quoting with { }. No characters have to (or can) be escaped.
\r
1661 // Thus the string cannot contain a '}' character.
\r
1681 } else if (ch == '\'' || ch == '"') {
\r
1682 // Quoting with ' ' or " ", with \ as escape character.
\r
1683 // Inconvenient for long strings that may contain Windows filenames.
\r
1700 if (ch == start) {
\r
1709 if (ad->argType == ArgFilename
\r
1710 || ad->argType == ArgSettingsFilename) {
\r
1716 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1740 for (i = 0; i < 3; i++) {
\r
1741 if (ch >= '0' && ch <= '7') {
\r
1742 octval = octval*8 + (ch - '0');
\r
1749 *q++ = (char) octval;
\r
1760 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1767 switch (ad->argType) {
\r
1769 *(int *) ad->argLoc = atoi(argValue);
\r
1773 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1781 *(int *) ad->argLoc = atoi(argValue);
\r
1782 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1786 *(float *) ad->argLoc = (float) atof(argValue);
\r
1791 *(char **) ad->argLoc = strdup(argValue);
\r
1794 case ArgSettingsFilename:
\r
1796 char fullname[MSG_SIZ];
\r
1797 if (ParseSettingsFile(argValue, fullname)) {
\r
1798 if (ad->argLoc != NULL) {
\r
1799 *(char **) ad->argLoc = strdup(fullname);
\r
1802 if (ad->argLoc != NULL) {
\r
1804 ExitArgError("Failed to open indirection file", argValue);
\r
1811 switch (argValue[0]) {
\r
1814 *(Boolean *) ad->argLoc = TRUE;
\r
1818 *(Boolean *) ad->argLoc = FALSE;
\r
1821 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1827 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1830 case ArgAttribs: {
\r
1831 ColorClass cc = (ColorClass)ad->argLoc;
\r
1832 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1836 case ArgBoardSize:
\r
1837 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1841 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1844 case ArgCommSettings:
\r
1845 ParseCommSettings(argValue, &dcb);
\r
1849 ExitArgError("Unrecognized argument", argValue);
\r
1858 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1860 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1861 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1864 lf->lfEscapement = 0;
\r
1865 lf->lfOrientation = 0;
\r
1866 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1867 lf->lfItalic = mfp->italic;
\r
1868 lf->lfUnderline = mfp->underline;
\r
1869 lf->lfStrikeOut = mfp->strikeout;
\r
1870 lf->lfCharSet = DEFAULT_CHARSET;
\r
1871 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1872 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1873 lf->lfQuality = DEFAULT_QUALITY;
\r
1874 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1875 strcpy(lf->lfFaceName, mfp->faceName);
\r
1879 CreateFontInMF(MyFont *mf)
\r
1881 LFfromMFP(&mf->lf, &mf->mfp);
\r
1882 if (mf->hf) DeleteObject(mf->hf);
\r
1883 mf->hf = CreateFontIndirect(&mf->lf);
\r
1887 SetDefaultTextAttribs()
\r
1890 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1891 ParseAttribs(&textAttribs[cc].color,
\r
1892 &textAttribs[cc].effects,
\r
1893 defaultTextAttribs[cc]);
\r
1898 SetDefaultSounds()
\r
1902 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1903 textAttribs[cc].sound.name = strdup("");
\r
1904 textAttribs[cc].sound.data = NULL;
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 sounds[sc].name = strdup("");
\r
1908 sounds[sc].data = NULL;
\r
1910 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 MyLoadSound(&textAttribs[cc].sound);
\r
1921 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1922 MyLoadSound(&sounds[sc]);
\r
1927 InitAppData(LPSTR lpCmdLine)
\r
1930 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1933 programName = szAppName;
\r
1935 /* Initialize to defaults */
\r
1936 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1937 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1938 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1939 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1940 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1941 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1942 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1943 SetDefaultTextAttribs();
\r
1944 SetDefaultSounds();
\r
1945 appData.movesPerSession = MOVES_PER_SESSION;
\r
1946 appData.initString = INIT_STRING;
\r
1947 appData.secondInitString = INIT_STRING;
\r
1948 appData.firstComputerString = COMPUTER_STRING;
\r
1949 appData.secondComputerString = COMPUTER_STRING;
\r
1950 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1951 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1952 appData.firstPlaysBlack = FALSE;
\r
1953 appData.noChessProgram = FALSE;
\r
1954 chessProgram = FALSE;
\r
1955 appData.firstHost = FIRST_HOST;
\r
1956 appData.secondHost = SECOND_HOST;
\r
1957 appData.firstDirectory = FIRST_DIRECTORY;
\r
1958 appData.secondDirectory = SECOND_DIRECTORY;
\r
1959 appData.bitmapDirectory = "";
\r
1960 appData.remoteShell = REMOTE_SHELL;
\r
1961 appData.remoteUser = "";
\r
1962 appData.timeDelay = TIME_DELAY;
\r
1963 appData.timeControl = TIME_CONTROL;
\r
1964 appData.timeIncrement = TIME_INCREMENT;
\r
1965 appData.icsActive = FALSE;
\r
1966 appData.icsHost = "";
\r
1967 appData.icsPort = ICS_PORT;
\r
1968 appData.icsCommPort = ICS_COMM_PORT;
\r
1969 appData.icsLogon = ICS_LOGON;
\r
1970 appData.icsHelper = "";
\r
1971 appData.useTelnet = FALSE;
\r
1972 appData.telnetProgram = TELNET_PROGRAM;
\r
1973 appData.gateway = "";
\r
1974 appData.loadGameFile = "";
\r
1975 appData.loadGameIndex = 0;
\r
1976 appData.saveGameFile = "";
\r
1977 appData.autoSaveGames = FALSE;
\r
1978 appData.loadPositionFile = "";
\r
1979 appData.loadPositionIndex = 1;
\r
1980 appData.savePositionFile = "";
\r
1981 appData.matchMode = FALSE;
\r
1982 appData.matchGames = 0;
\r
1983 appData.monoMode = FALSE;
\r
1984 appData.debugMode = FALSE;
\r
1985 appData.clockMode = TRUE;
\r
1986 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1987 appData.Iconic = FALSE; /*unused*/
\r
1988 appData.searchTime = "";
\r
1989 appData.searchDepth = 0;
\r
1990 appData.showCoords = FALSE;
\r
1991 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1992 appData.autoCallFlag = FALSE;
\r
1993 appData.flipView = FALSE;
\r
1994 appData.autoFlipView = TRUE;
\r
1995 appData.cmailGameName = "";
\r
1996 appData.alwaysPromoteToQueen = FALSE;
\r
1997 appData.oldSaveStyle = FALSE;
\r
1998 appData.quietPlay = FALSE;
\r
1999 appData.showThinking = FALSE;
\r
2000 appData.ponderNextMove = TRUE;
\r
2001 appData.periodicUpdates = TRUE;
\r
2002 appData.popupExitMessage = TRUE;
\r
2003 appData.popupMoveErrors = FALSE;
\r
2004 appData.autoObserve = FALSE;
\r
2005 appData.autoComment = FALSE;
\r
2006 appData.animate = TRUE;
\r
2007 appData.animSpeed = 10;
\r
2008 appData.animateDragging = TRUE;
\r
2009 appData.highlightLastMove = TRUE;
\r
2010 appData.getMoveList = TRUE;
\r
2011 appData.testLegality = TRUE;
\r
2012 appData.premove = TRUE;
\r
2013 appData.premoveWhite = FALSE;
\r
2014 appData.premoveWhiteText = "";
\r
2015 appData.premoveBlack = FALSE;
\r
2016 appData.premoveBlackText = "";
\r
2017 appData.icsAlarm = TRUE;
\r
2018 appData.icsAlarmTime = 5000;
\r
2019 appData.autoRaiseBoard = TRUE;
\r
2020 appData.localLineEditing = TRUE;
\r
2021 appData.colorize = TRUE;
\r
2022 appData.reuseFirst = TRUE;
\r
2023 appData.reuseSecond = TRUE;
\r
2024 appData.blindfold = FALSE;
\r
2025 appData.icsEngineAnalyze = FALSE;
\r
2026 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2027 dcb.DCBlength = sizeof(DCB);
\r
2028 dcb.BaudRate = 9600;
\r
2029 dcb.fBinary = TRUE;
\r
2030 dcb.fParity = FALSE;
\r
2031 dcb.fOutxCtsFlow = FALSE;
\r
2032 dcb.fOutxDsrFlow = FALSE;
\r
2033 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2034 dcb.fDsrSensitivity = FALSE;
\r
2035 dcb.fTXContinueOnXoff = TRUE;
\r
2036 dcb.fOutX = FALSE;
\r
2038 dcb.fNull = FALSE;
\r
2039 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2040 dcb.fAbortOnError = FALSE;
\r
2042 dcb.Parity = SPACEPARITY;
\r
2043 dcb.StopBits = ONESTOPBIT;
\r
2044 settingsFileName = SETTINGS_FILE;
\r
2045 saveSettingsOnExit = TRUE;
\r
2046 boardX = CW_USEDEFAULT;
\r
2047 boardY = CW_USEDEFAULT;
\r
2048 analysisX = CW_USEDEFAULT;
\r
2049 analysisY = CW_USEDEFAULT;
\r
2050 analysisW = CW_USEDEFAULT;
\r
2051 analysisH = CW_USEDEFAULT;
\r
2052 commentX = CW_USEDEFAULT;
\r
2053 commentY = CW_USEDEFAULT;
\r
2054 commentW = CW_USEDEFAULT;
\r
2055 commentH = CW_USEDEFAULT;
\r
2056 editTagsX = CW_USEDEFAULT;
\r
2057 editTagsY = CW_USEDEFAULT;
\r
2058 editTagsW = CW_USEDEFAULT;
\r
2059 editTagsH = CW_USEDEFAULT;
\r
2060 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2061 icsNames = ICS_NAMES;
\r
2062 firstChessProgramNames = FCP_NAMES;
\r
2063 secondChessProgramNames = SCP_NAMES;
\r
2064 appData.initialMode = "";
\r
2065 appData.variant = "normal";
\r
2066 appData.firstProtocolVersion = PROTOVER;
\r
2067 appData.secondProtocolVersion = PROTOVER;
\r
2068 appData.showButtonBar = TRUE;
\r
2070 /* [AS] New properties (see comments in header file) */
\r
2071 appData.firstScoreIsAbsolute = FALSE;
\r
2072 appData.secondScoreIsAbsolute = FALSE;
\r
2073 appData.saveExtendedInfoInPGN = FALSE;
\r
2074 appData.hideThinkingFromHuman = FALSE;
\r
2075 appData.liteBackTextureFile = "";
\r
2076 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2077 appData.darkBackTextureFile = "";
\r
2078 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2079 appData.renderPiecesWithFont = "";
\r
2080 appData.fontToPieceTable = "";
\r
2081 appData.fontBackColorWhite = 0;
\r
2082 appData.fontForeColorWhite = 0;
\r
2083 appData.fontBackColorBlack = 0;
\r
2084 appData.fontForeColorBlack = 0;
\r
2085 appData.fontPieceSize = 80;
\r
2086 appData.overrideLineGap = 1;
\r
2087 appData.adjudicateLossThreshold = 0;
\r
2088 appData.delayBeforeQuit = 0;
\r
2089 appData.delayAfterQuit = 0;
\r
2090 appData.nameOfDebugFile = "winboard.debug";
\r
2091 appData.pgnEventHeader = "Computer Chess Game";
\r
2092 appData.defaultFrcPosition = -1;
\r
2093 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2094 appData.saveOutOfBookInfo = TRUE;
\r
2095 appData.showEvalInMoveHistory = TRUE;
\r
2096 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2097 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2098 appData.highlightMoveWithArrow = FALSE;
\r
2099 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2100 appData.useStickyWindows = TRUE;
\r
2101 appData.adjudicateDrawMoves = 0;
\r
2102 appData.autoDisplayComment = TRUE;
\r
2103 appData.autoDisplayTags = TRUE;
\r
2104 appData.firstIsUCI = FALSE;
\r
2105 appData.secondIsUCI = FALSE;
\r
2106 appData.firstHasOwnBookUCI = TRUE;
\r
2107 appData.secondHasOwnBookUCI = TRUE;
\r
2108 appData.polyglotDir = "";
\r
2109 appData.usePolyglotBook = FALSE;
\r
2110 appData.polyglotBook = "";
\r
2111 appData.defaultHashSize = 64;
\r
2112 appData.defaultCacheSizeEGTB = 4;
\r
2113 appData.defaultPathEGTB = "c:\\egtb";
\r
2114 appData.firstOptions = "";
\r
2115 appData.secondOptions = "";
\r
2117 InitWindowPlacement( &wpGameList );
\r
2118 InitWindowPlacement( &wpMoveHistory );
\r
2119 InitWindowPlacement( &wpEvalGraph );
\r
2120 InitWindowPlacement( &wpEngineOutput );
\r
2121 InitWindowPlacement( &wpConsole );
\r
2123 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2124 appData.NrFiles = -1;
\r
2125 appData.NrRanks = -1;
\r
2126 appData.holdingsSize = -1;
\r
2127 appData.testClaims = FALSE;
\r
2128 appData.checkMates = FALSE;
\r
2129 appData.materialDraws= FALSE;
\r
2130 appData.trivialDraws = FALSE;
\r
2131 appData.ruleMoves = 51;
\r
2132 appData.drawRepeats = 6;
\r
2133 appData.matchPause = 10000;
\r
2134 appData.alphaRank = FALSE;
\r
2135 appData.allWhite = FALSE;
\r
2136 appData.upsideDown = FALSE;
\r
2137 appData.serverPause = 15;
\r
2138 appData.serverMovesName = NULL;
\r
2139 appData.suppressLoadMoves = FALSE;
\r
2140 appData.firstTimeOdds = 1;
\r
2141 appData.secondTimeOdds = 1;
\r
2142 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2143 appData.secondAccumulateTC = 1;
\r
2144 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2145 appData.secondNPS = -1;
\r
2146 appData.engineComments = 1;
\r
2147 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2148 appData.egtFormats = "";
\r
2151 appData.zippyTalk = ZIPPY_TALK;
\r
2152 appData.zippyPlay = ZIPPY_PLAY;
\r
2153 appData.zippyLines = ZIPPY_LINES;
\r
2154 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2155 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2156 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2157 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2158 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2159 appData.zippyUseI = ZIPPY_USE_I;
\r
2160 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2161 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2162 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2163 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2164 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2165 appData.zippyAbort = ZIPPY_ABORT;
\r
2166 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2167 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2168 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2171 /* Point font array elements to structures and
\r
2172 parse default font names */
\r
2173 for (i=0; i<NUM_FONTS; i++) {
\r
2174 for (j=0; j<NUM_SIZES; j++) {
\r
2175 font[j][i] = &fontRec[j][i];
\r
2176 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2180 /* Parse default settings file if any */
\r
2181 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2182 settingsFileName = strdup(buf);
\r
2185 /* Parse command line */
\r
2186 ParseArgs(StringGet, &lpCmdLine);
\r
2188 /* [HGM] make sure board size is acceptable */
\r
2189 if(appData.NrFiles > BOARD_SIZE ||
\r
2190 appData.NrRanks > BOARD_SIZE )
\r
2191 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2193 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2194 * with options from the command line, we now make an even higher priority
\r
2195 * overrule by WB options attached to the engine command line. This so that
\r
2196 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2199 if(appData.firstChessProgram != NULL) {
\r
2200 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2201 static char *f = "first";
\r
2202 char buf[MSG_SIZ], *q = buf;
\r
2203 if(p != NULL) { // engine command line contains WinBoard options
\r
2204 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2205 ParseArgs(StringGet, &q);
\r
2206 p[-1] = 0; // cut them offengine command line
\r
2209 // now do same for second chess program
\r
2210 if(appData.secondChessProgram != NULL) {
\r
2211 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2212 static char *s = "second";
\r
2213 char buf[MSG_SIZ], *q = buf;
\r
2214 if(p != NULL) { // engine command line contains WinBoard options
\r
2215 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2216 ParseArgs(StringGet, &q);
\r
2217 p[-1] = 0; // cut them offengine command line
\r
2222 /* Propagate options that affect others */
\r
2223 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2224 if (appData.icsActive || appData.noChessProgram) {
\r
2225 chessProgram = FALSE; /* not local chess program mode */
\r
2228 /* Open startup dialog if needed */
\r
2229 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2230 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2231 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2232 *appData.secondChessProgram == NULLCHAR))) {
\r
2235 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2236 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2237 FreeProcInstance(lpProc);
\r
2240 /* Make sure save files land in the right (?) directory */
\r
2241 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2242 appData.saveGameFile = strdup(buf);
\r
2244 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.savePositionFile = strdup(buf);
\r
2248 /* Finish initialization for fonts and sounds */
\r
2249 for (i=0; i<NUM_FONTS; i++) {
\r
2250 for (j=0; j<NUM_SIZES; j++) {
\r
2251 CreateFontInMF(font[j][i]);
\r
2254 /* xboard, and older WinBoards, controlled the move sound with the
\r
2255 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2256 always turn the option on (so that the backend will call us),
\r
2257 then let the user turn the sound off by setting it to silence if
\r
2258 desired. To accommodate old winboard.ini files saved by old
\r
2259 versions of WinBoard, we also turn off the sound if the option
\r
2260 was initially set to false. */
\r
2261 if (!appData.ringBellAfterMoves) {
\r
2262 sounds[(int)SoundMove].name = strdup("");
\r
2263 appData.ringBellAfterMoves = TRUE;
\r
2265 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2266 SetCurrentDirectory(installDir);
\r
2268 SetCurrentDirectory(currDir);
\r
2270 p = icsTextMenuString;
\r
2271 if (p[0] == '@') {
\r
2272 FILE* f = fopen(p + 1, "r");
\r
2274 DisplayFatalError(p + 1, errno, 2);
\r
2277 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2279 buf[i] = NULLCHAR;
\r
2282 ParseIcsTextMenu(strdup(p));
\r
2289 HMENU hmenu = GetMenu(hwndMain);
\r
2291 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2292 MF_BYCOMMAND|((appData.icsActive &&
\r
2293 *appData.icsCommPort != NULLCHAR) ?
\r
2294 MF_ENABLED : MF_GRAYED));
\r
2295 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2296 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2297 MF_CHECKED : MF_UNCHECKED));
\r
2302 SaveSettings(char* name)
\r
2305 ArgDescriptor *ad;
\r
2306 WINDOWPLACEMENT wp;
\r
2307 char dir[MSG_SIZ];
\r
2309 if (!hwndMain) return;
\r
2311 GetCurrentDirectory(MSG_SIZ, dir);
\r
2312 SetCurrentDirectory(installDir);
\r
2313 f = fopen(name, "w");
\r
2314 SetCurrentDirectory(dir);
\r
2316 DisplayError(name, errno);
\r
2319 fprintf(f, ";\n");
\r
2320 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2321 fprintf(f, ";\n");
\r
2322 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2323 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2324 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2325 fprintf(f, ";\n");
\r
2327 wp.length = sizeof(WINDOWPLACEMENT);
\r
2328 GetWindowPlacement(hwndMain, &wp);
\r
2329 boardX = wp.rcNormalPosition.left;
\r
2330 boardY = wp.rcNormalPosition.top;
\r
2332 if (hwndConsole) {
\r
2333 GetWindowPlacement(hwndConsole, &wp);
\r
2334 wpConsole.x = wp.rcNormalPosition.left;
\r
2335 wpConsole.y = wp.rcNormalPosition.top;
\r
2336 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2337 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2340 if (analysisDialog) {
\r
2341 GetWindowPlacement(analysisDialog, &wp);
\r
2342 analysisX = wp.rcNormalPosition.left;
\r
2343 analysisY = wp.rcNormalPosition.top;
\r
2344 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2345 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2348 if (commentDialog) {
\r
2349 GetWindowPlacement(commentDialog, &wp);
\r
2350 commentX = wp.rcNormalPosition.left;
\r
2351 commentY = wp.rcNormalPosition.top;
\r
2352 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (editTagsDialog) {
\r
2357 GetWindowPlacement(editTagsDialog, &wp);
\r
2358 editTagsX = wp.rcNormalPosition.left;
\r
2359 editTagsY = wp.rcNormalPosition.top;
\r
2360 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (gameListDialog) {
\r
2365 GetWindowPlacement(gameListDialog, &wp);
\r
2366 wpGameList.x = wp.rcNormalPosition.left;
\r
2367 wpGameList.y = wp.rcNormalPosition.top;
\r
2368 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 /* [AS] Move history */
\r
2373 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2375 if( moveHistoryDialog ) {
\r
2376 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2377 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2378 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2379 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2380 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2383 /* [AS] Eval graph */
\r
2384 wpEvalGraph.visible = EvalGraphIsUp();
\r
2386 if( evalGraphDialog ) {
\r
2387 GetWindowPlacement(evalGraphDialog, &wp);
\r
2388 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2389 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2390 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2391 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2394 /* [AS] Engine output */
\r
2395 wpEngineOutput.visible = EngineOutputIsUp();
\r
2397 if( engineOutputDialog ) {
\r
2398 GetWindowPlacement(engineOutputDialog, &wp);
\r
2399 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2400 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2401 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2402 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2405 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2406 if (!ad->save) continue;
\r
2407 switch (ad->argType) {
\r
2410 char *p = *(char **)ad->argLoc;
\r
2411 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2412 /* Quote multiline values or \-containing values
\r
2413 with { } if possible */
\r
2414 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2416 /* Else quote with " " */
\r
2417 fprintf(f, "/%s=\"", ad->argName);
\r
2419 if (*p == '\n') fprintf(f, "\n");
\r
2420 else if (*p == '\r') fprintf(f, "\\r");
\r
2421 else if (*p == '\t') fprintf(f, "\\t");
\r
2422 else if (*p == '\b') fprintf(f, "\\b");
\r
2423 else if (*p == '\f') fprintf(f, "\\f");
\r
2424 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2425 else if (*p == '\"') fprintf(f, "\\\"");
\r
2426 else if (*p == '\\') fprintf(f, "\\\\");
\r
2430 fprintf(f, "\"\n");
\r
2436 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2445 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2448 fprintf(f, "/%s=%s\n", ad->argName,
\r
2449 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2452 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2455 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2460 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2461 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2466 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2467 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2468 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2469 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2470 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2471 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2472 (ta->effects) ? " " : "",
\r
2473 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2477 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2478 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2480 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2483 case ArgBoardSize:
\r
2484 fprintf(f, "/%s=%s\n", ad->argName,
\r
2485 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2490 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2491 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2492 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2493 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2494 ad->argName, mfp->faceName, mfp->pointSize,
\r
2495 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2496 mfp->bold ? "b" : "",
\r
2497 mfp->italic ? "i" : "",
\r
2498 mfp->underline ? "u" : "",
\r
2499 mfp->strikeout ? "s" : "");
\r
2503 case ArgCommSettings:
\r
2504 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2506 case ArgSettingsFilename: ;
\r
2514 /*---------------------------------------------------------------------------*\
\r
2516 * GDI board drawing routines
\r
2518 \*---------------------------------------------------------------------------*/
\r
2520 /* [AS] Draw square using background texture */
\r
2521 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2526 return; /* Should never happen! */
\r
2529 SetGraphicsMode( dst, GM_ADVANCED );
\r
2536 /* X reflection */
\r
2541 x.eDx = (FLOAT) dw + dx - 1;
\r
2544 SetWorldTransform( dst, &x );
\r
2547 /* Y reflection */
\r
2553 x.eDy = (FLOAT) dh + dy - 1;
\r
2555 SetWorldTransform( dst, &x );
\r
2563 x.eDx = (FLOAT) dx;
\r
2564 x.eDy = (FLOAT) dy;
\r
2567 SetWorldTransform( dst, &x );
\r
2571 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2579 SetWorldTransform( dst, &x );
\r
2581 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2584 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2586 PM_WP = (int) WhitePawn,
\r
2587 PM_WN = (int) WhiteKnight,
\r
2588 PM_WB = (int) WhiteBishop,
\r
2589 PM_WR = (int) WhiteRook,
\r
2590 PM_WQ = (int) WhiteQueen,
\r
2591 PM_WF = (int) WhiteFerz,
\r
2592 PM_WW = (int) WhiteWazir,
\r
2593 PM_WE = (int) WhiteAlfil,
\r
2594 PM_WM = (int) WhiteMan,
\r
2595 PM_WO = (int) WhiteCannon,
\r
2596 PM_WU = (int) WhiteUnicorn,
\r
2597 PM_WH = (int) WhiteNightrider,
\r
2598 PM_WA = (int) WhiteAngel,
\r
2599 PM_WC = (int) WhiteMarshall,
\r
2600 PM_WAB = (int) WhiteCardinal,
\r
2601 PM_WD = (int) WhiteDragon,
\r
2602 PM_WL = (int) WhiteLance,
\r
2603 PM_WS = (int) WhiteCobra,
\r
2604 PM_WV = (int) WhiteFalcon,
\r
2605 PM_WSG = (int) WhiteSilver,
\r
2606 PM_WG = (int) WhiteGrasshopper,
\r
2607 PM_WK = (int) WhiteKing,
\r
2608 PM_BP = (int) BlackPawn,
\r
2609 PM_BN = (int) BlackKnight,
\r
2610 PM_BB = (int) BlackBishop,
\r
2611 PM_BR = (int) BlackRook,
\r
2612 PM_BQ = (int) BlackQueen,
\r
2613 PM_BF = (int) BlackFerz,
\r
2614 PM_BW = (int) BlackWazir,
\r
2615 PM_BE = (int) BlackAlfil,
\r
2616 PM_BM = (int) BlackMan,
\r
2617 PM_BO = (int) BlackCannon,
\r
2618 PM_BU = (int) BlackUnicorn,
\r
2619 PM_BH = (int) BlackNightrider,
\r
2620 PM_BA = (int) BlackAngel,
\r
2621 PM_BC = (int) BlackMarshall,
\r
2622 PM_BG = (int) BlackGrasshopper,
\r
2623 PM_BAB = (int) BlackCardinal,
\r
2624 PM_BD = (int) BlackDragon,
\r
2625 PM_BL = (int) BlackLance,
\r
2626 PM_BS = (int) BlackCobra,
\r
2627 PM_BV = (int) BlackFalcon,
\r
2628 PM_BSG = (int) BlackSilver,
\r
2629 PM_BK = (int) BlackKing
\r
2632 static HFONT hPieceFont = NULL;
\r
2633 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2634 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2635 static int fontBitmapSquareSize = 0;
\r
2636 static char pieceToFontChar[(int) EmptySquare] =
\r
2637 { 'p', 'n', 'b', 'r', 'q',
\r
2638 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2639 'k', 'o', 'm', 'v', 't', 'w',
\r
2640 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2643 extern BOOL SetCharTable( char *table, const char * map );
\r
2644 /* [HGM] moved to backend.c */
\r
2646 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2649 BYTE r1 = GetRValue( color );
\r
2650 BYTE g1 = GetGValue( color );
\r
2651 BYTE b1 = GetBValue( color );
\r
2657 /* Create a uniform background first */
\r
2658 hbrush = CreateSolidBrush( color );
\r
2659 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject( hbrush );
\r
2664 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2665 int steps = squareSize / 2;
\r
2668 for( i=0; i<steps; i++ ) {
\r
2669 BYTE r = r1 - (r1-r2) * i / steps;
\r
2670 BYTE g = g1 - (g1-g2) * i / steps;
\r
2671 BYTE b = b1 - (b1-b2) * i / steps;
\r
2673 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2674 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2675 FillRect( hdc, &rc, hbrush );
\r
2676 DeleteObject(hbrush);
\r
2679 else if( mode == 2 ) {
\r
2680 /* Diagonal gradient, good more or less for every piece */
\r
2681 POINT triangle[3];
\r
2682 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2683 HBRUSH hbrush_old;
\r
2684 int steps = squareSize;
\r
2687 triangle[0].x = squareSize - steps;
\r
2688 triangle[0].y = squareSize;
\r
2689 triangle[1].x = squareSize;
\r
2690 triangle[1].y = squareSize;
\r
2691 triangle[2].x = squareSize;
\r
2692 triangle[2].y = squareSize - steps;
\r
2694 for( i=0; i<steps; i++ ) {
\r
2695 BYTE r = r1 - (r1-r2) * i / steps;
\r
2696 BYTE g = g1 - (g1-g2) * i / steps;
\r
2697 BYTE b = b1 - (b1-b2) * i / steps;
\r
2699 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2700 hbrush_old = SelectObject( hdc, hbrush );
\r
2701 Polygon( hdc, triangle, 3 );
\r
2702 SelectObject( hdc, hbrush_old );
\r
2703 DeleteObject(hbrush);
\r
2708 SelectObject( hdc, hpen );
\r
2713 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2714 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2715 piece: follow the steps as explained below.
\r
2717 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2721 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2725 int backColor = whitePieceColor;
\r
2726 int foreColor = blackPieceColor;
\r
2728 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2729 backColor = appData.fontBackColorWhite;
\r
2730 foreColor = appData.fontForeColorWhite;
\r
2732 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2733 backColor = appData.fontBackColorBlack;
\r
2734 foreColor = appData.fontForeColorBlack;
\r
2738 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2740 hbm_old = SelectObject( hdc, hbm );
\r
2744 rc.right = squareSize;
\r
2745 rc.bottom = squareSize;
\r
2747 /* Step 1: background is now black */
\r
2748 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2750 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2752 pt.x = (squareSize - sz.cx) / 2;
\r
2753 pt.y = (squareSize - sz.cy) / 2;
\r
2755 SetBkMode( hdc, TRANSPARENT );
\r
2756 SetTextColor( hdc, chroma );
\r
2757 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2758 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2760 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2761 /* Step 3: the area outside the piece is filled with white */
\r
2762 // FloodFill( hdc, 0, 0, chroma );
\r
2763 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2764 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2765 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2766 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2767 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2769 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2770 but if the start point is not inside the piece we're lost!
\r
2771 There should be a better way to do this... if we could create a region or path
\r
2772 from the fill operation we would be fine for example.
\r
2774 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2775 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2777 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2778 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2779 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2781 SelectObject( dc2, bm2 );
\r
2782 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2783 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2786 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 DeleteObject( bm2 );
\r
2792 SetTextColor( hdc, 0 );
\r
2794 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2795 draw the piece again in black for safety.
\r
2797 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2799 SelectObject( hdc, hbm_old );
\r
2801 if( hPieceMask[index] != NULL ) {
\r
2802 DeleteObject( hPieceMask[index] );
\r
2805 hPieceMask[index] = hbm;
\r
2808 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2810 SelectObject( hdc, hbm );
\r
2813 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2814 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2815 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2817 SelectObject( dc1, hPieceMask[index] );
\r
2818 SelectObject( dc2, bm2 );
\r
2819 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2820 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2823 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2824 the piece background and deletes (makes transparent) the rest.
\r
2825 Thanks to that mask, we are free to paint the background with the greates
\r
2826 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2827 We use this, to make gradients and give the pieces a "roundish" look.
\r
2829 SetPieceBackground( hdc, backColor, 2 );
\r
2830 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2834 DeleteObject( bm2 );
\r
2837 SetTextColor( hdc, foreColor );
\r
2838 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2840 SelectObject( hdc, hbm_old );
\r
2842 if( hPieceFace[index] != NULL ) {
\r
2843 DeleteObject( hPieceFace[index] );
\r
2846 hPieceFace[index] = hbm;
\r
2849 static int TranslatePieceToFontPiece( int piece )
\r
2879 case BlackMarshall:
\r
2883 case BlackNightrider:
\r
2889 case BlackUnicorn:
\r
2893 case BlackGrasshopper:
\r
2905 case BlackCardinal:
\r
2912 case WhiteMarshall:
\r
2916 case WhiteNightrider:
\r
2922 case WhiteUnicorn:
\r
2926 case WhiteGrasshopper:
\r
2938 case WhiteCardinal:
\r
2947 void CreatePiecesFromFont()
\r
2950 HDC hdc_window = NULL;
\r
2956 if( fontBitmapSquareSize < 0 ) {
\r
2957 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2961 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2962 fontBitmapSquareSize = -1;
\r
2966 if( fontBitmapSquareSize != squareSize ) {
\r
2967 hdc_window = GetDC( hwndMain );
\r
2968 hdc = CreateCompatibleDC( hdc_window );
\r
2970 if( hPieceFont != NULL ) {
\r
2971 DeleteObject( hPieceFont );
\r
2974 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2975 hPieceMask[i] = NULL;
\r
2976 hPieceFace[i] = NULL;
\r
2982 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2983 fontHeight = appData.fontPieceSize;
\r
2986 fontHeight = (fontHeight * squareSize) / 100;
\r
2988 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2990 lf.lfEscapement = 0;
\r
2991 lf.lfOrientation = 0;
\r
2992 lf.lfWeight = FW_NORMAL;
\r
2994 lf.lfUnderline = 0;
\r
2995 lf.lfStrikeOut = 0;
\r
2996 lf.lfCharSet = DEFAULT_CHARSET;
\r
2997 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2998 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2999 lf.lfQuality = PROOF_QUALITY;
\r
3000 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3001 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3002 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3004 hPieceFont = CreateFontIndirect( &lf );
\r
3006 if( hPieceFont == NULL ) {
\r
3007 fontBitmapSquareSize = -2;
\r
3010 /* Setup font-to-piece character table */
\r
3011 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3012 /* No (or wrong) global settings, try to detect the font */
\r
3013 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3015 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3017 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3018 /* DiagramTT* family */
\r
3019 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3021 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3022 /* Fairy symbols */
\r
3023 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3025 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3026 /* Good Companion (Some characters get warped as literal :-( */
\r
3027 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3028 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3029 SetCharTable(pieceToFontChar, s);
\r
3032 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3033 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3037 /* Create bitmaps */
\r
3038 hfont_old = SelectObject( hdc, hPieceFont );
\r
3039 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3040 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3043 SelectObject( hdc, hfont_old );
\r
3045 fontBitmapSquareSize = squareSize;
\r
3049 if( hdc != NULL ) {
\r
3053 if( hdc_window != NULL ) {
\r
3054 ReleaseDC( hwndMain, hdc_window );
\r
3059 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3063 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3064 if (gameInfo.event &&
\r
3065 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3066 strcmp(name, "k80s") == 0) {
\r
3067 strcpy(name, "tim");
\r
3069 return LoadBitmap(hinst, name);
\r
3073 /* Insert a color into the program's logical palette
\r
3074 structure. This code assumes the given color is
\r
3075 the result of the RGB or PALETTERGB macro, and it
\r
3076 knows how those macros work (which is documented).
\r
3079 InsertInPalette(COLORREF color)
\r
3081 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3083 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3084 DisplayFatalError("Too many colors", 0, 1);
\r
3085 pLogPal->palNumEntries--;
\r
3089 pe->peFlags = (char) 0;
\r
3090 pe->peRed = (char) (0xFF & color);
\r
3091 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3092 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3098 InitDrawingColors()
\r
3100 if (pLogPal == NULL) {
\r
3101 /* Allocate enough memory for a logical palette with
\r
3102 * PALETTESIZE entries and set the size and version fields
\r
3103 * of the logical palette structure.
\r
3105 pLogPal = (NPLOGPALETTE)
\r
3106 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3107 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3108 pLogPal->palVersion = 0x300;
\r
3110 pLogPal->palNumEntries = 0;
\r
3112 InsertInPalette(lightSquareColor);
\r
3113 InsertInPalette(darkSquareColor);
\r
3114 InsertInPalette(whitePieceColor);
\r
3115 InsertInPalette(blackPieceColor);
\r
3116 InsertInPalette(highlightSquareColor);
\r
3117 InsertInPalette(premoveHighlightColor);
\r
3119 /* create a logical color palette according the information
\r
3120 * in the LOGPALETTE structure.
\r
3122 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3124 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3125 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3126 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3127 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3128 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3129 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3130 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3131 /* [AS] Force rendering of the font-based pieces */
\r
3132 if( fontBitmapSquareSize > 0 ) {
\r
3133 fontBitmapSquareSize = 0;
\r
3139 BoardWidth(int boardSize, int n)
\r
3140 { /* [HGM] argument n added to allow different width and height */
\r
3141 int lineGap = sizeInfo[boardSize].lineGap;
\r
3143 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3144 lineGap = appData.overrideLineGap;
\r
3147 return (n + 1) * lineGap +
\r
3148 n * sizeInfo[boardSize].squareSize;
\r
3151 /* Respond to board resize by dragging edge */
\r
3153 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3155 BoardSize newSize = NUM_SIZES - 1;
\r
3156 static int recurse = 0;
\r
3157 if (IsIconic(hwndMain)) return;
\r
3158 if (recurse > 0) return;
\r
3160 while (newSize > 0) {
\r
3161 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3162 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3163 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3166 boardSize = newSize;
\r
3167 InitDrawingSizes(boardSize, flags);
\r
3174 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3176 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3177 ChessSquare piece;
\r
3178 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3180 SIZE clockSize, messageSize;
\r
3182 char buf[MSG_SIZ];
\r
3184 HMENU hmenu = GetMenu(hwndMain);
\r
3185 RECT crect, wrect, oldRect;
\r
3187 LOGBRUSH logbrush;
\r
3189 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3190 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3192 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3193 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3195 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3196 oldRect.top = boardY;
\r
3197 oldRect.right = boardX + winWidth;
\r
3198 oldRect.bottom = boardY + winHeight;
\r
3200 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3201 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3202 squareSize = sizeInfo[boardSize].squareSize;
\r
3203 lineGap = sizeInfo[boardSize].lineGap;
\r
3204 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3206 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3207 lineGap = appData.overrideLineGap;
\r
3210 if (tinyLayout != oldTinyLayout) {
\r
3211 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3213 style &= ~WS_SYSMENU;
\r
3214 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3215 "&Minimize\tCtrl+F4");
\r
3217 style |= WS_SYSMENU;
\r
3218 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3220 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3222 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3223 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3224 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3226 DrawMenuBar(hwndMain);
\r
3229 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3230 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3232 /* Get text area sizes */
\r
3233 hdc = GetDC(hwndMain);
\r
3234 if (appData.clockMode) {
\r
3235 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3237 sprintf(buf, "White");
\r
3239 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3240 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3241 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3242 str = "We only care about the height here";
\r
3243 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3244 SelectObject(hdc, oldFont);
\r
3245 ReleaseDC(hwndMain, hdc);
\r
3247 /* Compute where everything goes */
\r
3248 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3249 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3250 logoHeight = 2*clockSize.cy;
\r
3251 leftLogoRect.left = OUTER_MARGIN;
\r
3252 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3253 leftLogoRect.top = OUTER_MARGIN;
\r
3254 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3256 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3257 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3258 rightLogoRect.top = OUTER_MARGIN;
\r
3259 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3262 whiteRect.left = leftLogoRect.right;
\r
3263 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3264 whiteRect.top = OUTER_MARGIN;
\r
3265 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3267 blackRect.right = rightLogoRect.left;
\r
3268 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3269 blackRect.top = whiteRect.top;
\r
3270 blackRect.bottom = whiteRect.bottom;
\r
3272 whiteRect.left = OUTER_MARGIN;
\r
3273 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3274 whiteRect.top = OUTER_MARGIN;
\r
3275 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3277 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3278 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3279 blackRect.top = whiteRect.top;
\r
3280 blackRect.bottom = whiteRect.bottom;
\r
3283 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3284 if (appData.showButtonBar) {
\r
3285 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3286 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3288 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3290 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3291 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3293 boardRect.left = OUTER_MARGIN;
\r
3294 boardRect.right = boardRect.left + boardWidth;
\r
3295 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3296 boardRect.bottom = boardRect.top + boardHeight;
\r
3298 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3299 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3300 oldBoardSize = boardSize;
\r
3301 oldTinyLayout = tinyLayout;
\r
3302 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3303 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3304 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3305 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3306 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3307 winHeight = winH; // without disturbing window attachments
\r
3308 GetWindowRect(hwndMain, &wrect);
\r
3309 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3310 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3312 // [HGM] placement: let attached windows follow size change.
\r
3313 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3314 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3315 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3319 /* compensate if menu bar wrapped */
\r
3320 GetClientRect(hwndMain, &crect);
\r
3321 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3322 winHeight += offby;
\r
3324 case WMSZ_TOPLEFT:
\r
3325 SetWindowPos(hwndMain, NULL,
\r
3326 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3327 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3330 case WMSZ_TOPRIGHT:
\r
3332 SetWindowPos(hwndMain, NULL,
\r
3333 wrect.left, wrect.bottom - winHeight,
\r
3334 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3337 case WMSZ_BOTTOMLEFT:
\r
3339 SetWindowPos(hwndMain, NULL,
\r
3340 wrect.right - winWidth, wrect.top,
\r
3341 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3344 case WMSZ_BOTTOMRIGHT:
\r
3348 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3349 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3354 for (i = 0; i < N_BUTTONS; i++) {
\r
3355 if (buttonDesc[i].hwnd != NULL) {
\r
3356 DestroyWindow(buttonDesc[i].hwnd);
\r
3357 buttonDesc[i].hwnd = NULL;
\r
3359 if (appData.showButtonBar) {
\r
3360 buttonDesc[i].hwnd =
\r
3361 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3362 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3363 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3364 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3365 (HMENU) buttonDesc[i].id,
\r
3366 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3368 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3369 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3370 MAKELPARAM(FALSE, 0));
\r
3372 if (buttonDesc[i].id == IDM_Pause)
\r
3373 hwndPause = buttonDesc[i].hwnd;
\r
3374 buttonDesc[i].wndproc = (WNDPROC)
\r
3375 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3378 if (gridPen != NULL) DeleteObject(gridPen);
\r
3379 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3380 if (premovePen != NULL) DeleteObject(premovePen);
\r
3381 if (lineGap != 0) {
\r
3382 logbrush.lbStyle = BS_SOLID;
\r
3383 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3385 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3386 lineGap, &logbrush, 0, NULL);
\r
3387 logbrush.lbColor = highlightSquareColor;
\r
3389 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3390 lineGap, &logbrush, 0, NULL);
\r
3392 logbrush.lbColor = premoveHighlightColor;
\r
3394 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3395 lineGap, &logbrush, 0, NULL);
\r
3397 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3398 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3399 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3400 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3401 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3402 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3403 BOARD_WIDTH * (squareSize + lineGap);
\r
3404 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3406 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3407 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3408 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3409 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3410 lineGap / 2 + (i * (squareSize + lineGap));
\r
3411 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3412 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3413 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3417 /* [HGM] Licensing requirement */
\r
3419 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3422 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3424 GothicPopUp( "", VariantNormal);
\r
3427 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3429 /* Load piece bitmaps for this board size */
\r
3430 for (i=0; i<=2; i++) {
\r
3431 for (piece = WhitePawn;
\r
3432 (int) piece < (int) BlackPawn;
\r
3433 piece = (ChessSquare) ((int) piece + 1)) {
\r
3434 if (pieceBitmap[i][piece] != NULL)
\r
3435 DeleteObject(pieceBitmap[i][piece]);
\r
3439 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3440 // Orthodox Chess pieces
\r
3441 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3442 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3443 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3444 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3446 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3451 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3452 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3454 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3456 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3457 // in Shogi, Hijack the unused Queen for Lance
\r
3458 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3459 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3460 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3462 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3463 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3464 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3467 if(squareSize <= 72 && squareSize >= 33) {
\r
3468 /* A & C are available in most sizes now */
\r
3469 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3470 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3482 } else { // Smirf-like
\r
3483 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3487 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3488 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3491 } else { // WinBoard standard
\r
3492 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3499 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3500 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3515 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3531 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3532 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3559 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3560 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3561 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3562 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3563 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3564 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3565 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3566 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3567 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3568 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3569 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3570 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3577 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3578 /* special Shogi support in this size */
\r
3579 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3580 for (piece = WhitePawn;
\r
3581 (int) piece < (int) BlackPawn;
\r
3582 piece = (ChessSquare) ((int) piece + 1)) {
\r
3583 if (pieceBitmap[i][piece] != NULL)
\r
3584 DeleteObject(pieceBitmap[i][piece]);
\r
3587 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3588 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3589 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3590 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3601 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3602 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3603 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3604 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3615 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3616 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3617 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3618 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3634 PieceBitmap(ChessSquare p, int kind)
\r
3636 if ((int) p >= (int) BlackPawn)
\r
3637 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3639 return pieceBitmap[kind][(int) p];
\r
3642 /***************************************************************/
\r
3644 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3645 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3647 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3648 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3652 SquareToPos(int row, int column, int * x, int * y)
\r
3655 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3656 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3658 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3659 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3664 DrawCoordsOnDC(HDC hdc)
\r
3666 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
3667 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
3668 char str[2] = { NULLCHAR, NULLCHAR };
\r
3669 int oldMode, oldAlign, x, y, start, i;
\r
3673 if (!appData.showCoords)
\r
3676 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3678 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3679 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3680 oldAlign = GetTextAlign(hdc);
\r
3681 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3683 y = boardRect.top + lineGap;
\r
3684 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3686 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3687 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3688 str[0] = files[start + i];
\r
3689 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3690 y += squareSize + lineGap;
\r
3693 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3695 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3696 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3697 str[0] = ranks[start + i];
\r
3698 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3699 x += squareSize + lineGap;
\r
3702 SelectObject(hdc, oldBrush);
\r
3703 SetBkMode(hdc, oldMode);
\r
3704 SetTextAlign(hdc, oldAlign);
\r
3705 SelectObject(hdc, oldFont);
\r
3709 DrawGridOnDC(HDC hdc)
\r
3713 if (lineGap != 0) {
\r
3714 oldPen = SelectObject(hdc, gridPen);
\r
3715 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3716 SelectObject(hdc, oldPen);
\r
3720 #define HIGHLIGHT_PEN 0
\r
3721 #define PREMOVE_PEN 1
\r
3724 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3727 HPEN oldPen, hPen;
\r
3728 if (lineGap == 0) return;
\r
3730 x1 = boardRect.left +
\r
3731 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3732 y1 = boardRect.top +
\r
3733 lineGap/2 + y * (squareSize + lineGap);
\r
3735 x1 = boardRect.left +
\r
3736 lineGap/2 + x * (squareSize + lineGap);
\r
3737 y1 = boardRect.top +
\r
3738 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3740 hPen = pen ? premovePen : highlightPen;
\r
3741 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3742 MoveToEx(hdc, x1, y1, NULL);
\r
3743 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3744 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3745 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3746 LineTo(hdc, x1, y1);
\r
3747 SelectObject(hdc, oldPen);
\r
3751 DrawHighlightsOnDC(HDC hdc)
\r
3754 for (i=0; i<2; i++) {
\r
3755 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3756 DrawHighlightOnDC(hdc, TRUE,
\r
3757 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3760 for (i=0; i<2; i++) {
\r
3761 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3762 premoveHighlightInfo.sq[i].y >= 0) {
\r
3763 DrawHighlightOnDC(hdc, TRUE,
\r
3764 premoveHighlightInfo.sq[i].x,
\r
3765 premoveHighlightInfo.sq[i].y,
\r
3771 /* Note: sqcolor is used only in monoMode */
\r
3772 /* Note that this code is largely duplicated in woptions.c,
\r
3773 function DrawSampleSquare, so that needs to be updated too */
\r
3775 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3777 HBITMAP oldBitmap;
\r
3781 if (appData.blindfold) return;
\r
3783 /* [AS] Use font-based pieces if needed */
\r
3784 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3785 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3786 CreatePiecesFromFont();
\r
3788 if( fontBitmapSquareSize == squareSize ) {
\r
3789 int index = TranslatePieceToFontPiece(piece);
\r
3791 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3795 squareSize, squareSize,
\r
3800 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3804 squareSize, squareSize,
\r
3813 if (appData.monoMode) {
\r
3814 SelectObject(tmphdc, PieceBitmap(piece,
\r
3815 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3816 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3817 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3819 tmpSize = squareSize;
\r
3821 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3822 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3823 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3824 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3825 x += (squareSize - minorSize)>>1;
\r
3826 y += squareSize - minorSize - 2;
\r
3827 tmpSize = minorSize;
\r
3829 if (color || appData.allWhite ) {
\r
3830 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3832 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3833 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3834 if(appData.upsideDown && color==flipView)
\r
3835 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3837 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3838 /* Use black for outline of white pieces */
\r
3839 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3840 if(appData.upsideDown && color==flipView)
\r
3841 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3843 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3845 /* Use square color for details of black pieces */
\r
3846 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3847 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3848 if(appData.upsideDown && !flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3853 SelectObject(hdc, oldBrush);
\r
3854 SelectObject(tmphdc, oldBitmap);
\r
3858 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3859 int GetBackTextureMode( int algo )
\r
3861 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3865 case BACK_TEXTURE_MODE_PLAIN:
\r
3866 result = 1; /* Always use identity map */
\r
3868 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3869 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3877 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3878 to handle redraws cleanly (as random numbers would always be different).
\r
3880 VOID RebuildTextureSquareInfo()
\r
3890 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3892 if( liteBackTexture != NULL ) {
\r
3893 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3894 lite_w = bi.bmWidth;
\r
3895 lite_h = bi.bmHeight;
\r
3899 if( darkBackTexture != NULL ) {
\r
3900 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3901 dark_w = bi.bmWidth;
\r
3902 dark_h = bi.bmHeight;
\r
3906 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3907 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3908 if( (col + row) & 1 ) {
\r
3910 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3911 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3912 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3913 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3918 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3928 /* [AS] Arrow highlighting support */
\r
3930 static int A_WIDTH = 5; /* Width of arrow body */
\r
3932 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3933 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3935 static double Sqr( double x )
\r
3940 static int Round( double x )
\r
3942 return (int) (x + 0.5);
\r
3945 /* Draw an arrow between two points using current settings */
\r
3946 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3949 double dx, dy, j, k, x, y;
\r
3951 if( d_x == s_x ) {
\r
3952 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3954 arrow[0].x = s_x + A_WIDTH;
\r
3957 arrow[1].x = s_x + A_WIDTH;
\r
3958 arrow[1].y = d_y - h;
\r
3960 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3961 arrow[2].y = d_y - h;
\r
3966 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3967 arrow[4].y = d_y - h;
\r
3969 arrow[5].x = s_x - A_WIDTH;
\r
3970 arrow[5].y = d_y - h;
\r
3972 arrow[6].x = s_x - A_WIDTH;
\r
3975 else if( d_y == s_y ) {
\r
3976 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3979 arrow[0].y = s_y + A_WIDTH;
\r
3981 arrow[1].x = d_x - w;
\r
3982 arrow[1].y = s_y + A_WIDTH;
\r
3984 arrow[2].x = d_x - w;
\r
3985 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3990 arrow[4].x = d_x - w;
\r
3991 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3993 arrow[5].x = d_x - w;
\r
3994 arrow[5].y = s_y - A_WIDTH;
\r
3997 arrow[6].y = s_y - A_WIDTH;
\r
4000 /* [AS] Needed a lot of paper for this! :-) */
\r
4001 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4002 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4004 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4006 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4011 arrow[0].x = Round(x - j);
\r
4012 arrow[0].y = Round(y + j*dx);
\r
4014 arrow[1].x = Round(x + j);
\r
4015 arrow[1].y = Round(y - j*dx);
\r
4018 x = (double) d_x - k;
\r
4019 y = (double) d_y - k*dy;
\r
4022 x = (double) d_x + k;
\r
4023 y = (double) d_y + k*dy;
\r
4026 arrow[2].x = Round(x + j);
\r
4027 arrow[2].y = Round(y - j*dx);
\r
4029 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4030 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4035 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4036 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4038 arrow[6].x = Round(x - j);
\r
4039 arrow[6].y = Round(y + j*dx);
\r
4042 Polygon( hdc, arrow, 7 );
\r
4045 /* [AS] Draw an arrow between two squares */
\r
4046 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4048 int s_x, s_y, d_x, d_y;
\r
4055 if( s_col == d_col && s_row == d_row ) {
\r
4059 /* Get source and destination points */
\r
4060 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4061 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4064 d_y += squareSize / 4;
\r
4066 else if( d_y < s_y ) {
\r
4067 d_y += 3 * squareSize / 4;
\r
4070 d_y += squareSize / 2;
\r
4074 d_x += squareSize / 4;
\r
4076 else if( d_x < s_x ) {
\r
4077 d_x += 3 * squareSize / 4;
\r
4080 d_x += squareSize / 2;
\r
4083 s_x += squareSize / 2;
\r
4084 s_y += squareSize / 2;
\r
4086 /* Adjust width */
\r
4087 A_WIDTH = squareSize / 14;
\r
4090 stLB.lbStyle = BS_SOLID;
\r
4091 stLB.lbColor = appData.highlightArrowColor;
\r
4094 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4095 holdpen = SelectObject( hdc, hpen );
\r
4096 hbrush = CreateBrushIndirect( &stLB );
\r
4097 holdbrush = SelectObject( hdc, hbrush );
\r
4099 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4101 SelectObject( hdc, holdpen );
\r
4102 SelectObject( hdc, holdbrush );
\r
4103 DeleteObject( hpen );
\r
4104 DeleteObject( hbrush );
\r
4107 BOOL HasHighlightInfo()
\r
4109 BOOL result = FALSE;
\r
4111 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4112 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4120 BOOL IsDrawArrowEnabled()
\r
4122 BOOL result = FALSE;
\r
4124 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4131 VOID DrawArrowHighlight( HDC hdc )
\r
4133 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4134 DrawArrowBetweenSquares( hdc,
\r
4135 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4136 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4140 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4142 HRGN result = NULL;
\r
4144 if( HasHighlightInfo() ) {
\r
4145 int x1, y1, x2, y2;
\r
4146 int sx, sy, dx, dy;
\r
4148 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4149 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4151 sx = MIN( x1, x2 );
\r
4152 sy = MIN( y1, y2 );
\r
4153 dx = MAX( x1, x2 ) + squareSize;
\r
4154 dy = MAX( y1, y2 ) + squareSize;
\r
4156 result = CreateRectRgn( sx, sy, dx, dy );
\r
4163 Warning: this function modifies the behavior of several other functions.
\r
4165 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4166 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4167 repaint is scattered all over the place, which is not good for features such as
\r
4168 "arrow highlighting" that require a full repaint of the board.
\r
4170 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4171 user interaction, when speed is not so important) but especially to avoid errors
\r
4172 in the displayed graphics.
\r
4174 In such patched places, I always try refer to this function so there is a single
\r
4175 place to maintain knowledge.
\r
4177 To restore the original behavior, just return FALSE unconditionally.
\r
4179 BOOL IsFullRepaintPreferrable()
\r
4181 BOOL result = FALSE;
\r
4183 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4184 /* Arrow may appear on the board */
\r
4192 This function is called by DrawPosition to know whether a full repaint must
\r
4195 Only DrawPosition may directly call this function, which makes use of
\r
4196 some state information. Other function should call DrawPosition specifying
\r
4197 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4199 BOOL DrawPositionNeedsFullRepaint()
\r
4201 BOOL result = FALSE;
\r
4204 Probably a slightly better policy would be to trigger a full repaint
\r
4205 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4206 but animation is fast enough that it's difficult to notice.
\r
4208 if( animInfo.piece == EmptySquare ) {
\r
4209 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4218 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4220 int row, column, x, y, square_color, piece_color;
\r
4221 ChessSquare piece;
\r
4223 HDC texture_hdc = NULL;
\r
4225 /* [AS] Initialize background textures if needed */
\r
4226 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4227 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4228 if( backTextureSquareSize != squareSize
\r
4229 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4230 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4231 backTextureSquareSize = squareSize;
\r
4232 RebuildTextureSquareInfo();
\r
4235 texture_hdc = CreateCompatibleDC( hdc );
\r
4238 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4239 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4241 SquareToPos(row, column, &x, &y);
\r
4243 piece = board[row][column];
\r
4245 square_color = ((column + row) % 2) == 1;
\r
4246 if( gameInfo.variant == VariantXiangqi ) {
\r
4247 square_color = !InPalace(row, column);
\r
4248 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4249 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4251 piece_color = (int) piece < (int) BlackPawn;
\r
4254 /* [HGM] holdings file: light square or black */
\r
4255 if(column == BOARD_LEFT-2) {
\r
4256 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4259 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4263 if(column == BOARD_RGHT + 1 ) {
\r
4264 if( row < gameInfo.holdingsSize )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4271 if(column == BOARD_LEFT-1 ) /* left align */
\r
4272 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4273 else if( column == BOARD_RGHT) /* right align */
\r
4274 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4276 if (appData.monoMode) {
\r
4277 if (piece == EmptySquare) {
\r
4278 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4279 square_color ? WHITENESS : BLACKNESS);
\r
4281 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4284 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4285 /* [AS] Draw the square using a texture bitmap */
\r
4286 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4287 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4288 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4291 squareSize, squareSize,
\r
4294 backTextureSquareInfo[r][c].mode,
\r
4295 backTextureSquareInfo[r][c].x,
\r
4296 backTextureSquareInfo[r][c].y );
\r
4298 SelectObject( texture_hdc, hbm );
\r
4300 if (piece != EmptySquare) {
\r
4301 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4305 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4307 oldBrush = SelectObject(hdc, brush );
\r
4308 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4309 SelectObject(hdc, oldBrush);
\r
4310 if (piece != EmptySquare)
\r
4311 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4316 if( texture_hdc != NULL ) {
\r
4317 DeleteDC( texture_hdc );
\r
4321 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4322 void fputDW(FILE *f, int x)
\r
4324 fputc(x & 255, f);
\r
4325 fputc(x>>8 & 255, f);
\r
4326 fputc(x>>16 & 255, f);
\r
4327 fputc(x>>24 & 255, f);
\r
4330 #define MAX_CLIPS 200 /* more than enough */
\r
4333 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4335 // HBITMAP bufferBitmap;
\r
4340 int w = 100, h = 50;
\r
4342 if(logo == NULL) return;
\r
4343 // GetClientRect(hwndMain, &Rect);
\r
4344 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4345 // Rect.bottom-Rect.top+1);
\r
4346 tmphdc = CreateCompatibleDC(hdc);
\r
4347 hbm = SelectObject(tmphdc, logo);
\r
4348 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4352 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4353 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4354 SelectObject(tmphdc, hbm);
\r
4359 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4361 static Board lastReq, lastDrawn;
\r
4362 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4363 static int lastDrawnFlipView = 0;
\r
4364 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4365 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4368 HBITMAP bufferBitmap;
\r
4369 HBITMAP oldBitmap;
\r
4371 HRGN clips[MAX_CLIPS];
\r
4372 ChessSquare dragged_piece = EmptySquare;
\r
4374 /* I'm undecided on this - this function figures out whether a full
\r
4375 * repaint is necessary on its own, so there's no real reason to have the
\r
4376 * caller tell it that. I think this can safely be set to FALSE - but
\r
4377 * if we trust the callers not to request full repaints unnessesarily, then
\r
4378 * we could skip some clipping work. In other words, only request a full
\r
4379 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4380 * gamestart and similar) --Hawk
\r
4382 Boolean fullrepaint = repaint;
\r
4384 if( DrawPositionNeedsFullRepaint() ) {
\r
4385 fullrepaint = TRUE;
\r
4388 if (board == NULL) {
\r
4389 if (!lastReqValid) {
\r
4394 CopyBoard(lastReq, board);
\r
4398 if (doingSizing) {
\r
4402 if (IsIconic(hwndMain)) {
\r
4406 if (hdc == NULL) {
\r
4407 hdc = GetDC(hwndMain);
\r
4408 if (!appData.monoMode) {
\r
4409 SelectPalette(hdc, hPal, FALSE);
\r
4410 RealizePalette(hdc);
\r
4414 releaseDC = FALSE;
\r
4417 /* Create some work-DCs */
\r
4418 hdcmem = CreateCompatibleDC(hdc);
\r
4419 tmphdc = CreateCompatibleDC(hdc);
\r
4421 /* If dragging is in progress, we temporarely remove the piece */
\r
4422 /* [HGM] or temporarily decrease count if stacked */
\r
4423 /* !! Moved to before board compare !! */
\r
4424 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4425 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4426 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4427 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4428 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4430 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4431 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4432 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4434 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4437 /* Figure out which squares need updating by comparing the
\r
4438 * newest board with the last drawn board and checking if
\r
4439 * flipping has changed.
\r
4441 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4442 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4443 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4444 if (lastDrawn[row][column] != board[row][column]) {
\r
4445 SquareToPos(row, column, &x, &y);
\r
4446 clips[num_clips++] =
\r
4447 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4451 for (i=0; i<2; i++) {
\r
4452 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4453 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4454 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4455 lastDrawnHighlight.sq[i].y >= 0) {
\r
4456 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4457 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4458 clips[num_clips++] =
\r
4459 CreateRectRgn(x - lineGap, y - lineGap,
\r
4460 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4462 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4463 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4464 clips[num_clips++] =
\r
4465 CreateRectRgn(x - lineGap, y - lineGap,
\r
4466 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 for (i=0; i<2; i++) {
\r
4471 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4472 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4473 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4474 lastDrawnPremove.sq[i].y >= 0) {
\r
4475 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4476 lastDrawnPremove.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 (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4482 premoveHighlightInfo.sq[i].y >= 0) {
\r
4483 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4484 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4492 fullrepaint = TRUE;
\r
4495 /* Create a buffer bitmap - this is the actual bitmap
\r
4496 * being written to. When all the work is done, we can
\r
4497 * copy it to the real DC (the screen). This avoids
\r
4498 * the problems with flickering.
\r
4500 GetClientRect(hwndMain, &Rect);
\r
4501 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4502 Rect.bottom-Rect.top+1);
\r
4503 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4504 if (!appData.monoMode) {
\r
4505 SelectPalette(hdcmem, hPal, FALSE);
\r
4508 /* Create clips for dragging */
\r
4509 if (!fullrepaint) {
\r
4510 if (dragInfo.from.x >= 0) {
\r
4511 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4512 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4514 if (dragInfo.start.x >= 0) {
\r
4515 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4516 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4518 if (dragInfo.pos.x >= 0) {
\r
4519 x = dragInfo.pos.x - squareSize / 2;
\r
4520 y = dragInfo.pos.y - squareSize / 2;
\r
4521 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4523 if (dragInfo.lastpos.x >= 0) {
\r
4524 x = dragInfo.lastpos.x - squareSize / 2;
\r
4525 y = dragInfo.lastpos.y - squareSize / 2;
\r
4526 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4530 /* Are we animating a move?
\r
4532 * - remove the piece from the board (temporarely)
\r
4533 * - calculate the clipping region
\r
4535 if (!fullrepaint) {
\r
4536 if (animInfo.piece != EmptySquare) {
\r
4537 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4538 x = boardRect.left + animInfo.lastpos.x;
\r
4539 y = boardRect.top + animInfo.lastpos.y;
\r
4540 x2 = boardRect.left + animInfo.pos.x;
\r
4541 y2 = boardRect.top + animInfo.pos.y;
\r
4542 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4543 /* Slight kludge. The real problem is that after AnimateMove is
\r
4544 done, the position on the screen does not match lastDrawn.
\r
4545 This currently causes trouble only on e.p. captures in
\r
4546 atomic, where the piece moves to an empty square and then
\r
4547 explodes. The old and new positions both had an empty square
\r
4548 at the destination, but animation has drawn a piece there and
\r
4549 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4550 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4554 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4555 if (num_clips == 0)
\r
4556 fullrepaint = TRUE;
\r
4558 /* Set clipping on the memory DC */
\r
4559 if (!fullrepaint) {
\r
4560 SelectClipRgn(hdcmem, clips[0]);
\r
4561 for (x = 1; x < num_clips; x++) {
\r
4562 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4563 abort(); // this should never ever happen!
\r
4567 /* Do all the drawing to the memory DC */
\r
4568 if(explodeInfo.radius) { // [HGM] atomic
\r
4570 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4571 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4572 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4573 x += squareSize/2;
\r
4574 y += squareSize/2;
\r
4575 if(!fullrepaint) {
\r
4576 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4577 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4579 DrawGridOnDC(hdcmem);
\r
4580 DrawHighlightsOnDC(hdcmem);
\r
4581 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4582 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4583 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4584 SelectObject(hdcmem, oldBrush);
\r
4586 DrawGridOnDC(hdcmem);
\r
4587 DrawHighlightsOnDC(hdcmem);
\r
4588 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4591 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4592 if(appData.autoLogo) {
\r
4594 switch(gameMode) { // pick logos based on game mode
\r
4595 case IcsObserving:
\r
4596 whiteLogo = second.programLogo; // ICS logo
\r
4597 blackLogo = second.programLogo;
\r
4600 case IcsPlayingWhite:
\r
4601 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4602 blackLogo = second.programLogo; // ICS logo
\r
4604 case IcsPlayingBlack:
\r
4605 whiteLogo = second.programLogo; // ICS logo
\r
4606 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4608 case TwoMachinesPlay:
\r
4609 if(first.twoMachinesColor[0] == 'b') {
\r
4610 whiteLogo = second.programLogo;
\r
4611 blackLogo = first.programLogo;
\r
4614 case MachinePlaysWhite:
\r
4615 blackLogo = userLogo;
\r
4617 case MachinePlaysBlack:
\r
4618 whiteLogo = userLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4623 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4626 if( appData.highlightMoveWithArrow ) {
\r
4627 DrawArrowHighlight(hdcmem);
\r
4630 DrawCoordsOnDC(hdcmem);
\r
4632 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4633 /* to make sure lastDrawn contains what is actually drawn */
\r
4635 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4636 if (dragged_piece != EmptySquare) {
\r
4637 /* [HGM] or restack */
\r
4638 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4639 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4641 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4642 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4643 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4644 x = dragInfo.pos.x - squareSize / 2;
\r
4645 y = dragInfo.pos.y - squareSize / 2;
\r
4646 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4647 ((int) dragged_piece < (int) BlackPawn),
\r
4648 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4651 /* Put the animated piece back into place and draw it */
\r
4652 if (animInfo.piece != EmptySquare) {
\r
4653 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4654 x = boardRect.left + animInfo.pos.x;
\r
4655 y = boardRect.top + animInfo.pos.y;
\r
4656 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4657 ((int) animInfo.piece < (int) BlackPawn),
\r
4658 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4661 /* Release the bufferBitmap by selecting in the old bitmap
\r
4662 * and delete the memory DC
\r
4664 SelectObject(hdcmem, oldBitmap);
\r
4667 /* Set clipping on the target DC */
\r
4668 if (!fullrepaint) {
\r
4669 SelectClipRgn(hdc, clips[0]);
\r
4670 for (x = 1; x < num_clips; x++) {
\r
4671 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4672 abort(); // this should never ever happen!
\r
4676 /* Copy the new bitmap onto the screen in one go.
\r
4677 * This way we avoid any flickering
\r
4679 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4680 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4681 boardRect.right - boardRect.left,
\r
4682 boardRect.bottom - boardRect.top,
\r
4683 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4684 if(saveDiagFlag) {
\r
4685 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4686 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4688 GetObject(bufferBitmap, sizeof(b), &b);
\r
4689 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4690 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4691 bih.biWidth = b.bmWidth;
\r
4692 bih.biHeight = b.bmHeight;
\r
4694 bih.biBitCount = b.bmBitsPixel;
\r
4695 bih.biCompression = 0;
\r
4696 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4697 bih.biXPelsPerMeter = 0;
\r
4698 bih.biYPelsPerMeter = 0;
\r
4699 bih.biClrUsed = 0;
\r
4700 bih.biClrImportant = 0;
\r
4701 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4702 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4703 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4704 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4706 wb = b.bmWidthBytes;
\r
4708 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4709 int k = ((int*) pData)[i];
\r
4710 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4711 if(j >= 16) break;
\r
4713 if(j >= nrColors) nrColors = j+1;
\r
4715 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4717 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4718 for(w=0; w<(wb>>2); w+=2) {
\r
4719 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4720 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4721 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4722 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4723 pData[p++] = m | j<<4;
\r
4725 while(p&3) pData[p++] = 0;
\r
4728 wb = ((wb+31)>>5)<<2;
\r
4730 // write BITMAPFILEHEADER
\r
4731 fprintf(diagFile, "BM");
\r
4732 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4733 fputDW(diagFile, 0);
\r
4734 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4735 // write BITMAPINFOHEADER
\r
4736 fputDW(diagFile, 40);
\r
4737 fputDW(diagFile, b.bmWidth);
\r
4738 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4739 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4740 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 // write color table
\r
4749 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4750 // write bitmap data
\r
4751 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4752 fputc(pData[i], diagFile);
\r
4756 SelectObject(tmphdc, oldBitmap);
\r
4758 /* Massive cleanup */
\r
4759 for (x = 0; x < num_clips; x++)
\r
4760 DeleteObject(clips[x]);
\r
4763 DeleteObject(bufferBitmap);
\r
4766 ReleaseDC(hwndMain, hdc);
\r
4768 if (lastDrawnFlipView != flipView) {
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4775 /* CopyBoard(lastDrawn, board);*/
\r
4776 lastDrawnHighlight = highlightInfo;
\r
4777 lastDrawnPremove = premoveHighlightInfo;
\r
4778 lastDrawnFlipView = flipView;
\r
4779 lastDrawnValid = 1;
\r
4782 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4787 saveDiagFlag = 1; diagFile = f;
\r
4788 HDCDrawPosition(NULL, TRUE, NULL);
\r
4792 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4799 /*---------------------------------------------------------------------------*\
\r
4800 | CLIENT PAINT PROCEDURE
\r
4801 | This is the main event-handler for the WM_PAINT message.
\r
4803 \*---------------------------------------------------------------------------*/
\r
4805 PaintProc(HWND hwnd)
\r
4811 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4812 if (IsIconic(hwnd)) {
\r
4813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4815 if (!appData.monoMode) {
\r
4816 SelectPalette(hdc, hPal, FALSE);
\r
4817 RealizePalette(hdc);
\r
4819 HDCDrawPosition(hdc, 1, NULL);
\r
4821 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4822 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4823 ETO_CLIPPED|ETO_OPAQUE,
\r
4824 &messageRect, messageText, strlen(messageText), NULL);
\r
4825 SelectObject(hdc, oldFont);
\r
4826 DisplayBothClocks();
\r
4828 EndPaint(hwnd,&ps);
\r
4836 * If the user selects on a border boundary, return -1; if off the board,
\r
4837 * return -2. Otherwise map the event coordinate to the square.
\r
4838 * The offset boardRect.left or boardRect.top must already have been
\r
4839 * subtracted from x.
\r
4842 EventToSquare(int x)
\r
4849 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4851 x /= (squareSize + lineGap);
\r
4852 if (x >= BOARD_SIZE)
\r
4863 DropEnable dropEnables[] = {
\r
4864 { 'P', DP_Pawn, "Pawn" },
\r
4865 { 'N', DP_Knight, "Knight" },
\r
4866 { 'B', DP_Bishop, "Bishop" },
\r
4867 { 'R', DP_Rook, "Rook" },
\r
4868 { 'Q', DP_Queen, "Queen" },
\r
4872 SetupDropMenu(HMENU hmenu)
\r
4874 int i, count, enable;
\r
4876 extern char white_holding[], black_holding[];
\r
4877 char item[MSG_SIZ];
\r
4879 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4880 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4881 dropEnables[i].piece);
\r
4883 while (p && *p++ == dropEnables[i].piece) count++;
\r
4884 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4885 enable = count > 0 || !appData.testLegality
\r
4886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4887 && !appData.icsActive);
\r
4888 ModifyMenu(hmenu, dropEnables[i].command,
\r
4889 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4890 dropEnables[i].command, item);
\r
4894 /* Event handler for mouse messages */
\r
4896 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4900 static int recursive = 0;
\r
4902 // BOOLEAN needsRedraw = FALSE;
\r
4903 BOOLEAN saveAnimate;
\r
4904 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4905 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4906 ChessMove moveType;
\r
4909 if (message == WM_MBUTTONUP) {
\r
4910 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4911 to the middle button: we simulate pressing the left button too!
\r
4913 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4914 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4920 pt.x = LOWORD(lParam);
\r
4921 pt.y = HIWORD(lParam);
\r
4922 x = EventToSquare(pt.x - boardRect.left);
\r
4923 y = EventToSquare(pt.y - boardRect.top);
\r
4924 if (!flipView && y >= 0) {
\r
4925 y = BOARD_HEIGHT - 1 - y;
\r
4927 if (flipView && x >= 0) {
\r
4928 x = BOARD_WIDTH - 1 - x;
\r
4931 switch (message) {
\r
4932 case WM_LBUTTONDOWN:
\r
4933 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4934 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4935 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4936 if(gameInfo.holdingsWidth &&
\r
4937 (WhiteOnMove(currentMove)
\r
4938 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4939 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4940 // click in right holdings, for determining promotion piece
\r
4941 ChessSquare p = boards[currentMove][y][x];
\r
4942 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4943 if(p != EmptySquare) {
\r
4944 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4945 fromX = fromY = -1;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4953 sameAgain = FALSE;
\r
4955 /* Downclick vertically off board; check if on clock */
\r
4956 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4957 if (gameMode == EditPosition) {
\r
4958 SetWhiteToPlayEvent();
\r
4959 } else if (gameMode == IcsPlayingBlack ||
\r
4960 gameMode == MachinePlaysWhite) {
\r
4962 } else if (gameMode == EditGame) {
\r
4963 AdjustClock(flipClock, -1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditPosition) {
\r
4967 SetBlackToPlayEvent();
\r
4968 } else if (gameMode == IcsPlayingWhite ||
\r
4969 gameMode == MachinePlaysBlack) {
\r
4971 } else if (gameMode == EditGame) {
\r
4972 AdjustClock(!flipClock, -1);
\r
4975 if (!appData.highlightLastMove) {
\r
4976 ClearHighlights();
\r
4977 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4979 fromX = fromY = -1;
\r
4980 dragInfo.start.x = dragInfo.start.y = -1;
\r
4981 dragInfo.from = dragInfo.start;
\r
4983 } else if (x < 0 || y < 0
\r
4984 /* [HGM] block clicks between board and holdings */
\r
4985 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4986 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4987 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4988 /* EditPosition, empty square, or different color piece;
\r
4989 click-click move is possible */
\r
4992 } else if (fromX == x && fromY == y) {
\r
4993 /* Downclick on same square again */
\r
4994 ClearHighlights();
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4996 sameAgain = TRUE;
\r
4997 } else if (fromX != -1 &&
\r
4998 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5000 /* Downclick on different square. */
\r
5001 /* [HGM] if on holdings file, should count as new first click ! */
\r
5002 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5005 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5006 to make sure move is legal before showing promotion popup */
\r
5007 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5008 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5009 fromX = fromY = -1;
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, boards[currentMove]);
\r
5014 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5015 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5016 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5017 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5018 appData.alwaysPromoteToQueen)) {
\r
5019 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5020 if (!appData.highlightLastMove) {
\r
5021 ClearHighlights();
\r
5022 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5025 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5026 SetHighlights(fromX, fromY, toX, toY);
\r
5027 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5028 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5029 If promotion to Q is legal, all are legal! */
\r
5030 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5031 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5032 // kludge to temporarily execute move on display, without promoting yet
\r
5033 promotionChoice = TRUE;
\r
5034 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5035 boards[currentMove][toY][toX] = p;
\r
5036 DrawPosition(FALSE, boards[currentMove]);
\r
5037 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5038 boards[currentMove][toY][toX] = q;
\r
5039 DisplayMessage("Select piece from holdings", "");
\r
5041 PromotionPopup(hwnd);
\r
5043 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5044 if (appData.animate || appData.highlightLastMove) {
\r
5045 SetHighlights(fromX, fromY, toX, toY);
\r
5047 ClearHighlights();
\r
5049 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5050 if (appData.animate && !appData.highlightLastMove) {
\r
5051 ClearHighlights();
\r
5052 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5055 fromX = fromY = -1;
\r
5059 if (gotPremove && moveType != Comment) {
\r
5060 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5062 } else ClearHighlights();
\r
5063 fromX = fromY = -1;
\r
5064 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5065 if(moveType != Comment) break;
\r
5067 /* First downclick, or restart on a square with same color piece */
\r
5068 if (!frozen && OKToStartUserMove(x, y)) {
\r
5071 dragInfo.lastpos = pt;
\r
5072 dragInfo.from.x = fromX;
\r
5073 dragInfo.from.y = fromY;
\r
5074 dragInfo.start = dragInfo.from;
\r
5075 SetCapture(hwndMain);
\r
5077 fromX = fromY = -1;
\r
5078 dragInfo.start.x = dragInfo.start.y = -1;
\r
5079 dragInfo.from = dragInfo.start;
\r
5080 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5084 case WM_LBUTTONUP:
\r
5086 if (fromX == -1) break;
\r
5087 if (x == fromX && y == fromY) {
\r
5088 dragInfo.from.x = dragInfo.from.y = -1;
\r
5089 /* Upclick on same square */
\r
5091 /* Clicked same square twice: abort click-click move */
\r
5092 fromX = fromY = -1;
\r
5094 ClearPremoveHighlights();
\r
5096 /* First square clicked: start click-click move */
\r
5097 SetHighlights(fromX, fromY, -1, -1);
\r
5099 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5100 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5101 /* Errant click; ignore */
\r
5104 /* Finish drag move. */
\r
5105 if (appData.debugMode) {
\r
5106 fprintf(debugFP, "release\n");
\r
5108 dragInfo.from.x = dragInfo.from.y = -1;
\r
5111 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5112 appData.animate = appData.animate && !appData.animateDragging;
\r
5113 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5114 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5115 fromX = fromY = -1;
\r
5116 ClearHighlights();
\r
5117 DrawPosition(FALSE, boards[currentMove]);
\r
5118 appData.animate = saveAnimate;
\r
5121 if(moveType != ImpossibleMove) {
\r
5122 /* [HGM] use move type to determine if move is promotion.
\r
5123 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5124 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5125 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5126 appData.alwaysPromoteToQueen))
\r
5127 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5129 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5130 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5132 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5133 // kludge to temporarily execute move on display, wthout promotng yet
\r
5134 promotionChoice = TRUE;
\r
5135 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5136 boards[currentMove][toY][toX] = p;
\r
5137 DrawPosition(FALSE, boards[currentMove]);
\r
5138 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5139 boards[currentMove][toY][toX] = q;
\r
5140 appData.animate = saveAnimate;
\r
5141 DisplayMessage("Select piece from holdings", "");
\r
5144 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5146 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5147 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5148 moveType == WhiteCapturesEnPassant ||
\r
5149 moveType == BlackCapturesEnPassant ) )
\r
5150 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5151 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5154 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5155 appData.animate = saveAnimate;
\r
5156 fromX = fromY = -1;
\r
5157 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5158 ClearHighlights();
\r
5160 if (appData.animate || appData.animateDragging ||
\r
5161 appData.highlightDragging || gotPremove) {
\r
5162 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5165 dragInfo.start.x = dragInfo.start.y = -1;
\r
5166 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5169 case WM_MOUSEMOVE:
\r
5170 if ((appData.animateDragging || appData.highlightDragging)
\r
5171 && (wParam & MK_LBUTTON)
\r
5172 && dragInfo.from.x >= 0)
\r
5174 BOOL full_repaint = FALSE;
\r
5176 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5177 if (appData.animateDragging) {
\r
5178 dragInfo.pos = pt;
\r
5180 if (appData.highlightDragging) {
\r
5181 SetHighlights(fromX, fromY, x, y);
\r
5182 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5183 full_repaint = TRUE;
\r
5187 DrawPosition( full_repaint, NULL);
\r
5189 dragInfo.lastpos = dragInfo.pos;
\r
5193 case WM_MOUSEWHEEL: // [DM]
\r
5194 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5195 /* Mouse Wheel is being rolled forward
\r
5196 * Play moves forward
\r
5198 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5199 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5200 /* Mouse Wheel is being rolled backward
\r
5201 * Play moves backward
\r
5203 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5204 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5208 case WM_MBUTTONDOWN:
\r
5209 case WM_RBUTTONDOWN:
\r
5212 fromX = fromY = -1;
\r
5213 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5214 dragInfo.start.x = dragInfo.start.y = -1;
\r
5215 dragInfo.from = dragInfo.start;
\r
5216 dragInfo.lastpos = dragInfo.pos;
\r
5217 if (appData.highlightDragging) {
\r
5218 ClearHighlights();
\r
5221 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5222 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5223 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5224 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5225 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5228 DrawPosition(TRUE, NULL);
\r
5230 switch (gameMode) {
\r
5231 case EditPosition:
\r
5232 case IcsExamining:
\r
5233 if (x < 0 || y < 0) break;
\r
5236 if (message == WM_MBUTTONDOWN) {
\r
5237 buttonCount = 3; /* even if system didn't think so */
\r
5238 if (wParam & MK_SHIFT)
\r
5239 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5241 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5242 } else { /* message == WM_RBUTTONDOWN */
\r
5243 /* Just have one menu, on the right button. Windows users don't
\r
5244 think to try the middle one, and sometimes other software steals
\r
5245 it, or it doesn't really exist. */
\r
5246 if(gameInfo.variant != VariantShogi)
\r
5247 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5249 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5252 case IcsPlayingWhite:
\r
5253 case IcsPlayingBlack:
\r
5255 case MachinePlaysWhite:
\r
5256 case MachinePlaysBlack:
\r
5257 if (appData.testLegality &&
\r
5258 gameInfo.variant != VariantBughouse &&
\r
5259 gameInfo.variant != VariantCrazyhouse) break;
\r
5260 if (x < 0 || y < 0) break;
\r
5263 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5264 SetupDropMenu(hmenu);
\r
5265 MenuPopup(hwnd, pt, hmenu, -1);
\r
5276 /* Preprocess messages for buttons in main window */
\r
5278 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5280 int id = GetWindowLong(hwnd, GWL_ID);
\r
5283 for (i=0; i<N_BUTTONS; i++) {
\r
5284 if (buttonDesc[i].id == id) break;
\r
5286 if (i == N_BUTTONS) return 0;
\r
5287 switch (message) {
\r
5292 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5293 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5300 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5303 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5304 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5305 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5306 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5308 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5310 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5311 PopUpMoveDialog((char)wParam);
\r
5317 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5320 /* Process messages for Promotion dialog box */
\r
5322 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5326 switch (message) {
\r
5327 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5328 /* Center the dialog over the application window */
\r
5329 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5330 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5331 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5332 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5333 SW_SHOW : SW_HIDE);
\r
5334 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5335 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5336 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5337 PieceToChar(WhiteAngel) != '~') ||
\r
5338 (PieceToChar(BlackAngel) >= 'A' &&
\r
5339 PieceToChar(BlackAngel) != '~') ) ?
\r
5340 SW_SHOW : SW_HIDE);
\r
5341 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5342 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5343 PieceToChar(WhiteMarshall) != '~') ||
\r
5344 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5345 PieceToChar(BlackMarshall) != '~') ) ?
\r
5346 SW_SHOW : SW_HIDE);
\r
5347 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5348 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5349 gameInfo.variant != VariantShogi ?
\r
5350 SW_SHOW : SW_HIDE);
\r
5351 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5352 gameInfo.variant != VariantShogi ?
\r
5353 SW_SHOW : SW_HIDE);
\r
5354 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5355 gameInfo.variant == VariantShogi ?
\r
5356 SW_SHOW : SW_HIDE);
\r
5357 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5358 gameInfo.variant == VariantShogi ?
\r
5359 SW_SHOW : SW_HIDE);
\r
5360 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5361 gameInfo.variant == VariantSuper ?
\r
5362 SW_SHOW : SW_HIDE);
\r
5365 case WM_COMMAND: /* message: received a command */
\r
5366 switch (LOWORD(wParam)) {
\r
5368 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5369 ClearHighlights();
\r
5370 DrawPosition(FALSE, NULL);
\r
5373 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5376 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5379 promoChar = PieceToChar(BlackRook);
\r
5382 promoChar = PieceToChar(BlackBishop);
\r
5384 case PB_Chancellor:
\r
5385 promoChar = PieceToChar(BlackMarshall);
\r
5387 case PB_Archbishop:
\r
5388 promoChar = PieceToChar(BlackAngel);
\r
5391 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5396 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5397 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5398 only show the popup when we are already sure the move is valid or
\r
5399 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5400 will figure out it is a promotion from the promoChar. */
\r
5401 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5402 if (!appData.highlightLastMove) {
\r
5403 ClearHighlights();
\r
5404 DrawPosition(FALSE, NULL);
\r
5411 /* Pop up promotion dialog */
\r
5413 PromotionPopup(HWND hwnd)
\r
5417 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5418 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5419 hwnd, (DLGPROC)lpProc);
\r
5420 FreeProcInstance(lpProc);
\r
5423 /* Toggle ShowThinking */
\r
5425 ToggleShowThinking()
\r
5427 appData.showThinking = !appData.showThinking;
\r
5428 ShowThinkingEvent();
\r
5432 LoadGameDialog(HWND hwnd, char* title)
\r
5436 char fileTitle[MSG_SIZ];
\r
5437 f = OpenFileDialog(hwnd, "rb", "",
\r
5438 appData.oldSaveStyle ? "gam" : "pgn",
\r
5440 title, &number, fileTitle, NULL);
\r
5442 cmailMsgLoaded = FALSE;
\r
5443 if (number == 0) {
\r
5444 int error = GameListBuild(f);
\r
5446 DisplayError("Cannot build game list", error);
\r
5447 } else if (!ListEmpty(&gameList) &&
\r
5448 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5449 GameListPopUp(f, fileTitle);
\r
5452 GameListDestroy();
\r
5455 LoadGame(f, number, fileTitle, FALSE);
\r
5459 void UpdateICSWidth(HWND hText)
\r
5464 HFONT hfont, hold_font;
\r
5465 LONG old_width, new_width;
\r
5467 // get the text metrics
\r
5468 hdc = GetDC(hText);
\r
5469 hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);
\r
5470 hold_font = SelectObject(hdc, hfont);
\r
5471 GetTextMetrics(hdc, &tm);
\r
5472 SelectObject(hdc, hold_font);
\r
5473 DeleteObject(hfont);
\r
5474 ReleaseDC(hText, hdc);
\r
5476 // get the rectangle
\r
5477 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5479 // update the width
\r
5480 new_width = (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5481 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5482 if (new_width != old_width)
\r
5484 ics_update_width(new_width);
\r
5485 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5490 ChangedConsoleFont()
\r
5493 CHARRANGE tmpsel, sel;
\r
5494 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5495 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5496 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5499 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5500 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5501 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5502 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5503 * size. This was undocumented in the version of MSVC++ that I had
\r
5504 * when I wrote the code, but is apparently documented now.
\r
5506 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5507 cfmt.bCharSet = f->lf.lfCharSet;
\r
5508 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5509 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5510 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5511 /* Why are the following seemingly needed too? */
\r
5512 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5513 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5514 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5516 tmpsel.cpMax = -1; /*999999?*/
\r
5517 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5518 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5519 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5520 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5522 paraf.cbSize = sizeof(paraf);
\r
5523 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5524 paraf.dxStartIndent = 0;
\r
5525 paraf.dxOffset = WRAP_INDENT;
\r
5526 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5527 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5528 UpdateICSWidth(hText);
\r
5531 /*---------------------------------------------------------------------------*\
\r
5533 * Window Proc for main window
\r
5535 \*---------------------------------------------------------------------------*/
\r
5537 /* Process messages for main window, etc. */
\r
5539 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5542 int wmId, wmEvent;
\r
5546 char fileTitle[MSG_SIZ];
\r
5547 char buf[MSG_SIZ];
\r
5548 static SnapData sd;
\r
5550 switch (message) {
\r
5552 case WM_PAINT: /* message: repaint portion of window */
\r
5556 case WM_ERASEBKGND:
\r
5557 if (IsIconic(hwnd)) {
\r
5558 /* Cheat; change the message */
\r
5559 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5561 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5565 case WM_LBUTTONDOWN:
\r
5566 case WM_MBUTTONDOWN:
\r
5567 case WM_RBUTTONDOWN:
\r
5568 case WM_LBUTTONUP:
\r
5569 case WM_MBUTTONUP:
\r
5570 case WM_RBUTTONUP:
\r
5571 case WM_MOUSEMOVE:
\r
5572 case WM_MOUSEWHEEL:
\r
5573 MouseEvent(hwnd, message, wParam, lParam);
\r
5576 JAWS_KB_NAVIGATION
\r
5580 JAWS_ALT_INTERCEPT
\r
5582 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5583 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5584 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5585 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5587 SendMessage(h, message, wParam, lParam);
\r
5588 } else if(lParam != KF_REPEAT) {
\r
5589 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5590 PopUpMoveDialog((char)wParam);
\r
5591 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5592 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5597 case WM_PALETTECHANGED:
\r
5598 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5600 HDC hdc = GetDC(hwndMain);
\r
5601 SelectPalette(hdc, hPal, TRUE);
\r
5602 nnew = RealizePalette(hdc);
\r
5604 paletteChanged = TRUE;
\r
5605 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5607 ReleaseDC(hwnd, hdc);
\r
5611 case WM_QUERYNEWPALETTE:
\r
5612 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5614 HDC hdc = GetDC(hwndMain);
\r
5615 paletteChanged = FALSE;
\r
5616 SelectPalette(hdc, hPal, FALSE);
\r
5617 nnew = RealizePalette(hdc);
\r
5619 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5621 ReleaseDC(hwnd, hdc);
\r
5626 case WM_COMMAND: /* message: command from application menu */
\r
5627 wmId = LOWORD(wParam);
\r
5628 wmEvent = HIWORD(wParam);
\r
5633 AnalysisPopDown();
\r
5634 SAY("new game enter a move to play against the computer with white");
\r
5637 case IDM_NewGameFRC:
\r
5638 if( NewGameFRC() == 0 ) {
\r
5640 AnalysisPopDown();
\r
5644 case IDM_NewVariant:
\r
5645 NewVariantPopup(hwnd);
\r
5648 case IDM_LoadGame:
\r
5649 LoadGameDialog(hwnd, "Load Game from File");
\r
5652 case IDM_LoadNextGame:
\r
5656 case IDM_LoadPrevGame:
\r
5660 case IDM_ReloadGame:
\r
5664 case IDM_LoadPosition:
\r
5665 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5666 Reset(FALSE, TRUE);
\r
5669 f = OpenFileDialog(hwnd, "rb", "",
\r
5670 appData.oldSaveStyle ? "pos" : "fen",
\r
5672 "Load Position from File", &number, fileTitle, NULL);
\r
5674 LoadPosition(f, number, fileTitle);
\r
5678 case IDM_LoadNextPosition:
\r
5679 ReloadPosition(1);
\r
5682 case IDM_LoadPrevPosition:
\r
5683 ReloadPosition(-1);
\r
5686 case IDM_ReloadPosition:
\r
5687 ReloadPosition(0);
\r
5690 case IDM_SaveGame:
\r
5691 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5692 f = OpenFileDialog(hwnd, "a", defName,
\r
5693 appData.oldSaveStyle ? "gam" : "pgn",
\r
5695 "Save Game to File", NULL, fileTitle, NULL);
\r
5697 SaveGame(f, 0, "");
\r
5701 case IDM_SavePosition:
\r
5702 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5703 f = OpenFileDialog(hwnd, "a", defName,
\r
5704 appData.oldSaveStyle ? "pos" : "fen",
\r
5706 "Save Position to File", NULL, fileTitle, NULL);
\r
5708 SavePosition(f, 0, "");
\r
5712 case IDM_SaveDiagram:
\r
5713 defName = "diagram";
\r
5714 f = OpenFileDialog(hwnd, "wb", defName,
\r
5717 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5723 case IDM_CopyGame:
\r
5724 CopyGameToClipboard();
\r
5727 case IDM_PasteGame:
\r
5728 PasteGameFromClipboard();
\r
5731 case IDM_CopyGameListToClipboard:
\r
5732 CopyGameListToClipboard();
\r
5735 /* [AS] Autodetect FEN or PGN data */
\r
5736 case IDM_PasteAny:
\r
5737 PasteGameOrFENFromClipboard();
\r
5740 /* [AS] Move history */
\r
5741 case IDM_ShowMoveHistory:
\r
5742 if( MoveHistoryIsUp() ) {
\r
5743 MoveHistoryPopDown();
\r
5746 MoveHistoryPopUp();
\r
5750 /* [AS] Eval graph */
\r
5751 case IDM_ShowEvalGraph:
\r
5752 if( EvalGraphIsUp() ) {
\r
5753 EvalGraphPopDown();
\r
5757 SetFocus(hwndMain);
\r
5761 /* [AS] Engine output */
\r
5762 case IDM_ShowEngineOutput:
\r
5763 if( EngineOutputIsUp() ) {
\r
5764 EngineOutputPopDown();
\r
5767 EngineOutputPopUp();
\r
5771 /* [AS] User adjudication */
\r
5772 case IDM_UserAdjudication_White:
\r
5773 UserAdjudicationEvent( +1 );
\r
5776 case IDM_UserAdjudication_Black:
\r
5777 UserAdjudicationEvent( -1 );
\r
5780 case IDM_UserAdjudication_Draw:
\r
5781 UserAdjudicationEvent( 0 );
\r
5784 /* [AS] Game list options dialog */
\r
5785 case IDM_GameListOptions:
\r
5786 GameListOptions();
\r
5793 case IDM_CopyPosition:
\r
5794 CopyFENToClipboard();
\r
5797 case IDM_PastePosition:
\r
5798 PasteFENFromClipboard();
\r
5801 case IDM_MailMove:
\r
5805 case IDM_ReloadCMailMsg:
\r
5806 Reset(TRUE, TRUE);
\r
5807 ReloadCmailMsgEvent(FALSE);
\r
5810 case IDM_Minimize:
\r
5811 ShowWindow(hwnd, SW_MINIMIZE);
\r
5818 case IDM_MachineWhite:
\r
5819 MachineWhiteEvent();
\r
5821 * refresh the tags dialog only if it's visible
\r
5823 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5825 tags = PGNTags(&gameInfo);
\r
5826 TagsPopUp(tags, CmailMsg());
\r
5829 SAY("computer starts playing white");
\r
5832 case IDM_MachineBlack:
\r
5833 MachineBlackEvent();
\r
5835 * refresh the tags dialog only if it's visible
\r
5837 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5839 tags = PGNTags(&gameInfo);
\r
5840 TagsPopUp(tags, CmailMsg());
\r
5843 SAY("computer starts playing black");
\r
5846 case IDM_TwoMachines:
\r
5847 TwoMachinesEvent();
\r
5849 * refresh the tags dialog only if it's visible
\r
5851 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5853 tags = PGNTags(&gameInfo);
\r
5854 TagsPopUp(tags, CmailMsg());
\r
5857 SAY("programs start playing each other");
\r
5860 case IDM_AnalysisMode:
\r
5861 if (!first.analysisSupport) {
\r
5862 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5863 DisplayError(buf, 0);
\r
5865 SAY("analyzing current position");
\r
5866 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5867 if (appData.icsActive) {
\r
5868 if (gameMode != IcsObserving) {
\r
5869 sprintf(buf, "You are not observing a game");
\r
5870 DisplayError(buf, 0);
\r
5871 /* secure check */
\r
5872 if (appData.icsEngineAnalyze) {
\r
5873 if (appData.debugMode)
\r
5874 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5875 ExitAnalyzeMode();
\r
5881 /* if enable, user want disable icsEngineAnalyze */
\r
5882 if (appData.icsEngineAnalyze) {
\r
5883 ExitAnalyzeMode();
\r
5887 appData.icsEngineAnalyze = TRUE;
\r
5888 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5891 if (!appData.showThinking) ToggleShowThinking();
\r
5892 AnalyzeModeEvent();
\r
5896 case IDM_AnalyzeFile:
\r
5897 if (!first.analysisSupport) {
\r
5898 char buf[MSG_SIZ];
\r
5899 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5900 DisplayError(buf, 0);
\r
5902 if (!appData.showThinking) ToggleShowThinking();
\r
5903 AnalyzeFileEvent();
\r
5904 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5905 AnalysisPeriodicEvent(1);
\r
5909 case IDM_IcsClient:
\r
5913 case IDM_EditGame:
\r
5918 case IDM_EditPosition:
\r
5919 EditPositionEvent();
\r
5920 SAY("to set up a position type a FEN");
\r
5923 case IDM_Training:
\r
5927 case IDM_ShowGameList:
\r
5928 ShowGameListProc();
\r
5931 case IDM_EditTags:
\r
5935 case IDM_EditComment:
\r
5936 if (commentDialogUp && editComment) {
\r
5939 EditCommentEvent();
\r
5959 case IDM_CallFlag:
\r
5979 case IDM_StopObserving:
\r
5980 StopObservingEvent();
\r
5983 case IDM_StopExamining:
\r
5984 StopExaminingEvent();
\r
5987 case IDM_TypeInMove:
\r
5988 PopUpMoveDialog('\000');
\r
5991 case IDM_TypeInName:
\r
5992 PopUpNameDialog('\000');
\r
5995 case IDM_Backward:
\r
5997 SetFocus(hwndMain);
\r
6004 SetFocus(hwndMain);
\r
6009 SetFocus(hwndMain);
\r
6014 SetFocus(hwndMain);
\r
6021 case IDM_TruncateGame:
\r
6022 TruncateGameEvent();
\r
6029 case IDM_RetractMove:
\r
6030 RetractMoveEvent();
\r
6033 case IDM_FlipView:
\r
6034 flipView = !flipView;
\r
6035 DrawPosition(FALSE, NULL);
\r
6038 case IDM_FlipClock:
\r
6039 flipClock = !flipClock;
\r
6040 DisplayBothClocks();
\r
6041 DrawPosition(FALSE, NULL);
\r
6044 case IDM_MuteSounds:
\r
6045 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6046 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6047 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6050 case IDM_GeneralOptions:
\r
6051 GeneralOptionsPopup(hwnd);
\r
6052 DrawPosition(TRUE, NULL);
\r
6055 case IDM_BoardOptions:
\r
6056 BoardOptionsPopup(hwnd);
\r
6059 case IDM_EnginePlayOptions:
\r
6060 EnginePlayOptionsPopup(hwnd);
\r
6063 case IDM_Engine1Options:
\r
6064 EngineOptionsPopup(hwnd, &first);
\r
6067 case IDM_Engine2Options:
\r
6068 EngineOptionsPopup(hwnd, &second);
\r
6071 case IDM_OptionsUCI:
\r
6072 UciOptionsPopup(hwnd);
\r
6075 case IDM_IcsOptions:
\r
6076 IcsOptionsPopup(hwnd);
\r
6080 FontsOptionsPopup(hwnd);
\r
6084 SoundOptionsPopup(hwnd);
\r
6087 case IDM_CommPort:
\r
6088 CommPortOptionsPopup(hwnd);
\r
6091 case IDM_LoadOptions:
\r
6092 LoadOptionsPopup(hwnd);
\r
6095 case IDM_SaveOptions:
\r
6096 SaveOptionsPopup(hwnd);
\r
6099 case IDM_TimeControl:
\r
6100 TimeControlOptionsPopup(hwnd);
\r
6103 case IDM_SaveSettings:
\r
6104 SaveSettings(settingsFileName);
\r
6107 case IDM_SaveSettingsOnExit:
\r
6108 saveSettingsOnExit = !saveSettingsOnExit;
\r
6109 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6110 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6111 MF_CHECKED : MF_UNCHECKED));
\r
6122 case IDM_AboutGame:
\r
6127 appData.debugMode = !appData.debugMode;
\r
6128 if (appData.debugMode) {
\r
6129 char dir[MSG_SIZ];
\r
6130 GetCurrentDirectory(MSG_SIZ, dir);
\r
6131 SetCurrentDirectory(installDir);
\r
6132 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6133 SetCurrentDirectory(dir);
\r
6134 setbuf(debugFP, NULL);
\r
6141 case IDM_HELPCONTENTS:
\r
6142 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6143 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6144 MessageBox (GetFocus(),
\r
6145 "Unable to activate help",
\r
6146 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6150 case IDM_HELPSEARCH:
\r
6151 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6152 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6153 MessageBox (GetFocus(),
\r
6154 "Unable to activate help",
\r
6155 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6159 case IDM_HELPHELP:
\r
6160 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6161 MessageBox (GetFocus(),
\r
6162 "Unable to activate help",
\r
6163 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6168 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6170 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6171 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6172 FreeProcInstance(lpProc);
\r
6175 case IDM_DirectCommand1:
\r
6176 AskQuestionEvent("Direct Command",
\r
6177 "Send to chess program:", "", "1");
\r
6179 case IDM_DirectCommand2:
\r
6180 AskQuestionEvent("Direct Command",
\r
6181 "Send to second chess program:", "", "2");
\r
6184 case EP_WhitePawn:
\r
6185 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6189 case EP_WhiteKnight:
\r
6190 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6194 case EP_WhiteBishop:
\r
6195 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6199 case EP_WhiteRook:
\r
6200 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6204 case EP_WhiteQueen:
\r
6205 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6209 case EP_WhiteFerz:
\r
6210 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6211 fromX = fromY = -1;
\r
6214 case EP_WhiteWazir:
\r
6215 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6216 fromX = fromY = -1;
\r
6219 case EP_WhiteAlfil:
\r
6220 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6221 fromX = fromY = -1;
\r
6224 case EP_WhiteCannon:
\r
6225 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6226 fromX = fromY = -1;
\r
6229 case EP_WhiteCardinal:
\r
6230 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6231 fromX = fromY = -1;
\r
6234 case EP_WhiteMarshall:
\r
6235 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6236 fromX = fromY = -1;
\r
6239 case EP_WhiteKing:
\r
6240 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6241 fromX = fromY = -1;
\r
6244 case EP_BlackPawn:
\r
6245 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6246 fromX = fromY = -1;
\r
6249 case EP_BlackKnight:
\r
6250 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6251 fromX = fromY = -1;
\r
6254 case EP_BlackBishop:
\r
6255 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6256 fromX = fromY = -1;
\r
6259 case EP_BlackRook:
\r
6260 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6261 fromX = fromY = -1;
\r
6264 case EP_BlackQueen:
\r
6265 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6266 fromX = fromY = -1;
\r
6269 case EP_BlackFerz:
\r
6270 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6271 fromX = fromY = -1;
\r
6274 case EP_BlackWazir:
\r
6275 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6276 fromX = fromY = -1;
\r
6279 case EP_BlackAlfil:
\r
6280 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6281 fromX = fromY = -1;
\r
6284 case EP_BlackCannon:
\r
6285 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6289 case EP_BlackCardinal:
\r
6290 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6294 case EP_BlackMarshall:
\r
6295 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6299 case EP_BlackKing:
\r
6300 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6304 case EP_EmptySquare:
\r
6305 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6309 case EP_ClearBoard:
\r
6310 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6315 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6320 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6325 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6330 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6331 fromX = fromY = -1;
\r
6335 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6336 fromX = fromY = -1;
\r
6340 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6341 fromX = fromY = -1;
\r
6345 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6346 fromX = fromY = -1;
\r
6350 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6351 fromX = fromY = -1;
\r
6355 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6356 fromX = fromY = -1;
\r
6360 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6366 case CLOCK_TIMER_ID:
\r
6367 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6368 clockTimerEvent = 0;
\r
6369 DecrementClocks(); /* call into back end */
\r
6371 case LOAD_GAME_TIMER_ID:
\r
6372 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6373 loadGameTimerEvent = 0;
\r
6374 AutoPlayGameLoop(); /* call into back end */
\r
6376 case ANALYSIS_TIMER_ID:
\r
6377 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6378 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6379 AnalysisPeriodicEvent(0);
\r
6381 KillTimer(hwnd, analysisTimerEvent);
\r
6382 analysisTimerEvent = 0;
\r
6385 case DELAYED_TIMER_ID:
\r
6386 KillTimer(hwnd, delayedTimerEvent);
\r
6387 delayedTimerEvent = 0;
\r
6388 delayedTimerCallback();
\r
6393 case WM_USER_Input:
\r
6394 InputEvent(hwnd, message, wParam, lParam);
\r
6397 /* [AS] Also move "attached" child windows */
\r
6398 case WM_WINDOWPOSCHANGING:
\r
6400 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6401 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6403 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6404 /* Window is moving */
\r
6407 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6408 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6409 rcMain.right = boardX + winWidth;
\r
6410 rcMain.top = boardY;
\r
6411 rcMain.bottom = boardY + winHeight;
\r
6413 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6414 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6415 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6416 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6417 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6424 /* [AS] Snapping */
\r
6425 case WM_ENTERSIZEMOVE:
\r
6426 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6427 if (hwnd == hwndMain) {
\r
6428 doingSizing = TRUE;
\r
6431 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6435 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6436 if (hwnd == hwndMain) {
\r
6437 lastSizing = wParam;
\r
6442 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6443 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6445 case WM_EXITSIZEMOVE:
\r
6446 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6447 if (hwnd == hwndMain) {
\r
6449 doingSizing = FALSE;
\r
6450 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6451 GetClientRect(hwnd, &client);
\r
6452 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6454 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6456 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6459 case WM_DESTROY: /* message: window being destroyed */
\r
6460 PostQuitMessage(0);
\r
6464 if (hwnd == hwndMain) {
\r
6469 default: /* Passes it on if unprocessed */
\r
6470 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6475 /*---------------------------------------------------------------------------*\
\r
6477 * Misc utility routines
\r
6479 \*---------------------------------------------------------------------------*/
\r
6482 * Decent random number generator, at least not as bad as Windows
\r
6483 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6485 unsigned int randstate;
\r
6490 randstate = randstate * 1664525 + 1013904223;
\r
6491 return (int) randstate & 0x7fffffff;
\r
6495 mysrandom(unsigned int seed)
\r
6502 * returns TRUE if user selects a different color, FALSE otherwise
\r
6506 ChangeColor(HWND hwnd, COLORREF *which)
\r
6508 static BOOL firstTime = TRUE;
\r
6509 static DWORD customColors[16];
\r
6511 COLORREF newcolor;
\r
6516 /* Make initial colors in use available as custom colors */
\r
6517 /* Should we put the compiled-in defaults here instead? */
\r
6519 customColors[i++] = lightSquareColor & 0xffffff;
\r
6520 customColors[i++] = darkSquareColor & 0xffffff;
\r
6521 customColors[i++] = whitePieceColor & 0xffffff;
\r
6522 customColors[i++] = blackPieceColor & 0xffffff;
\r
6523 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6524 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6526 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6527 customColors[i++] = textAttribs[ccl].color;
\r
6529 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6530 firstTime = FALSE;
\r
6533 cc.lStructSize = sizeof(cc);
\r
6534 cc.hwndOwner = hwnd;
\r
6535 cc.hInstance = NULL;
\r
6536 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6537 cc.lpCustColors = (LPDWORD) customColors;
\r
6538 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6540 if (!ChooseColor(&cc)) return FALSE;
\r
6542 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6543 if (newcolor == *which) return FALSE;
\r
6544 *which = newcolor;
\r
6548 InitDrawingColors();
\r
6549 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6554 MyLoadSound(MySound *ms)
\r
6560 if (ms->data) free(ms->data);
\r
6563 switch (ms->name[0]) {
\r
6569 /* System sound from Control Panel. Don't preload here. */
\r
6573 if (ms->name[1] == NULLCHAR) {
\r
6574 /* "!" alone = silence */
\r
6577 /* Builtin wave resource. Error if not found. */
\r
6578 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6579 if (h == NULL) break;
\r
6580 ms->data = (void *)LoadResource(hInst, h);
\r
6581 if (h == NULL) break;
\r
6586 /* .wav file. Error if not found. */
\r
6587 f = fopen(ms->name, "rb");
\r
6588 if (f == NULL) break;
\r
6589 if (fstat(fileno(f), &st) < 0) break;
\r
6590 ms->data = malloc(st.st_size);
\r
6591 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6597 char buf[MSG_SIZ];
\r
6598 sprintf(buf, "Error loading sound %s", ms->name);
\r
6599 DisplayError(buf, GetLastError());
\r
6605 MyPlaySound(MySound *ms)
\r
6607 BOOLEAN ok = FALSE;
\r
6609 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6610 switch (ms->name[0]) {
\r
6612 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6617 /* System sound from Control Panel (deprecated feature).
\r
6618 "$" alone or an unset sound name gets default beep (still in use). */
\r
6619 if (ms->name[1]) {
\r
6620 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6622 if (!ok) ok = MessageBeep(MB_OK);
\r
6625 /* Builtin wave resource, or "!" alone for silence */
\r
6626 if (ms->name[1]) {
\r
6627 if (ms->data == NULL) return FALSE;
\r
6628 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6634 /* .wav file. Error if not found. */
\r
6635 if (ms->data == NULL) return FALSE;
\r
6636 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6639 /* Don't print an error: this can happen innocently if the sound driver
\r
6640 is busy; for instance, if another instance of WinBoard is playing
\r
6641 a sound at about the same time. */
\r
6647 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6650 OPENFILENAME *ofn;
\r
6651 static UINT *number; /* gross that this is static */
\r
6653 switch (message) {
\r
6654 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6655 /* Center the dialog over the application window */
\r
6656 ofn = (OPENFILENAME *) lParam;
\r
6657 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6658 number = (UINT *) ofn->lCustData;
\r
6659 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6663 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6664 return FALSE; /* Allow for further processing */
\r
6667 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6668 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6670 return FALSE; /* Allow for further processing */
\r
6676 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6678 static UINT *number;
\r
6679 OPENFILENAME *ofname;
\r
6682 case WM_INITDIALOG:
\r
6683 ofname = (OPENFILENAME *)lParam;
\r
6684 number = (UINT *)(ofname->lCustData);
\r
6687 ofnot = (OFNOTIFY *)lParam;
\r
6688 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6689 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6698 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6699 char *nameFilt, char *dlgTitle, UINT *number,
\r
6700 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6702 OPENFILENAME openFileName;
\r
6703 char buf1[MSG_SIZ];
\r
6706 if (fileName == NULL) fileName = buf1;
\r
6707 if (defName == NULL) {
\r
6708 strcpy(fileName, "*.");
\r
6709 strcat(fileName, defExt);
\r
6711 strcpy(fileName, defName);
\r
6713 if (fileTitle) strcpy(fileTitle, "");
\r
6714 if (number) *number = 0;
\r
6716 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6717 openFileName.hwndOwner = hwnd;
\r
6718 openFileName.hInstance = (HANDLE) hInst;
\r
6719 openFileName.lpstrFilter = nameFilt;
\r
6720 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6721 openFileName.nMaxCustFilter = 0L;
\r
6722 openFileName.nFilterIndex = 1L;
\r
6723 openFileName.lpstrFile = fileName;
\r
6724 openFileName.nMaxFile = MSG_SIZ;
\r
6725 openFileName.lpstrFileTitle = fileTitle;
\r
6726 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6727 openFileName.lpstrInitialDir = NULL;
\r
6728 openFileName.lpstrTitle = dlgTitle;
\r
6729 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6730 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6731 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6732 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6733 openFileName.nFileOffset = 0;
\r
6734 openFileName.nFileExtension = 0;
\r
6735 openFileName.lpstrDefExt = defExt;
\r
6736 openFileName.lCustData = (LONG) number;
\r
6737 openFileName.lpfnHook = oldDialog ?
\r
6738 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6739 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6741 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6742 GetOpenFileName(&openFileName)) {
\r
6743 /* open the file */
\r
6744 f = fopen(openFileName.lpstrFile, write);
\r
6746 MessageBox(hwnd, "File open failed", NULL,
\r
6747 MB_OK|MB_ICONEXCLAMATION);
\r
6751 int err = CommDlgExtendedError();
\r
6752 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6761 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6763 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6766 * Get the first pop-up menu in the menu template. This is the
\r
6767 * menu that TrackPopupMenu displays.
\r
6769 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6771 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6774 * TrackPopup uses screen coordinates, so convert the
\r
6775 * coordinates of the mouse click to screen coordinates.
\r
6777 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6779 /* Draw and track the floating pop-up menu. */
\r
6780 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6781 pt.x, pt.y, 0, hwnd, NULL);
\r
6783 /* Destroy the menu.*/
\r
6784 DestroyMenu(hmenu);
\r
6789 int sizeX, sizeY, newSizeX, newSizeY;
\r
6791 } ResizeEditPlusButtonsClosure;
\r
6794 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6796 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6800 if (hChild == cl->hText) return TRUE;
\r
6801 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6802 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6803 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6804 ScreenToClient(cl->hDlg, &pt);
\r
6805 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6806 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6810 /* Resize a dialog that has a (rich) edit field filling most of
\r
6811 the top, with a row of buttons below */
\r
6813 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6816 int newTextHeight, newTextWidth;
\r
6817 ResizeEditPlusButtonsClosure cl;
\r
6819 /*if (IsIconic(hDlg)) return;*/
\r
6820 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6822 cl.hdwp = BeginDeferWindowPos(8);
\r
6824 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6825 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6826 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6827 if (newTextHeight < 0) {
\r
6828 newSizeY += -newTextHeight;
\r
6829 newTextHeight = 0;
\r
6831 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6832 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6838 cl.newSizeX = newSizeX;
\r
6839 cl.newSizeY = newSizeY;
\r
6840 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6842 EndDeferWindowPos(cl.hdwp);
\r
6845 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6847 RECT rChild, rParent;
\r
6848 int wChild, hChild, wParent, hParent;
\r
6849 int wScreen, hScreen, xNew, yNew;
\r
6852 /* Get the Height and Width of the child window */
\r
6853 GetWindowRect (hwndChild, &rChild);
\r
6854 wChild = rChild.right - rChild.left;
\r
6855 hChild = rChild.bottom - rChild.top;
\r
6857 /* Get the Height and Width of the parent window */
\r
6858 GetWindowRect (hwndParent, &rParent);
\r
6859 wParent = rParent.right - rParent.left;
\r
6860 hParent = rParent.bottom - rParent.top;
\r
6862 /* Get the display limits */
\r
6863 hdc = GetDC (hwndChild);
\r
6864 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6865 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6866 ReleaseDC(hwndChild, hdc);
\r
6868 /* Calculate new X position, then adjust for screen */
\r
6869 xNew = rParent.left + ((wParent - wChild) /2);
\r
6872 } else if ((xNew+wChild) > wScreen) {
\r
6873 xNew = wScreen - wChild;
\r
6876 /* Calculate new Y position, then adjust for screen */
\r
6878 yNew = rParent.top + ((hParent - hChild) /2);
\r
6881 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6886 } else if ((yNew+hChild) > hScreen) {
\r
6887 yNew = hScreen - hChild;
\r
6890 /* Set it, and return */
\r
6891 return SetWindowPos (hwndChild, NULL,
\r
6892 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6895 /* Center one window over another */
\r
6896 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6898 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6901 /*---------------------------------------------------------------------------*\
\r
6903 * Startup Dialog functions
\r
6905 \*---------------------------------------------------------------------------*/
\r
6907 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6909 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6911 while (*cd != NULL) {
\r
6912 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6918 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6920 char buf1[ARG_MAX];
\r
6923 if (str[0] == '@') {
\r
6924 FILE* f = fopen(str + 1, "r");
\r
6926 DisplayFatalError(str + 1, errno, 2);
\r
6929 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6931 buf1[len] = NULLCHAR;
\r
6935 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6938 char buf[MSG_SIZ];
\r
6939 char *end = strchr(str, '\n');
\r
6940 if (end == NULL) return;
\r
6941 memcpy(buf, str, end - str);
\r
6942 buf[end - str] = NULLCHAR;
\r
6943 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6949 SetStartupDialogEnables(HWND hDlg)
\r
6951 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6952 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6953 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6954 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6955 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6956 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6957 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6958 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6959 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6960 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6961 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6962 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6963 IsDlgButtonChecked(hDlg, OPT_View));
\r
6967 QuoteForFilename(char *filename)
\r
6969 int dquote, space;
\r
6970 dquote = strchr(filename, '"') != NULL;
\r
6971 space = strchr(filename, ' ') != NULL;
\r
6972 if (dquote || space) {
\r
6984 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6986 char buf[MSG_SIZ];
\r
6989 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6990 q = QuoteForFilename(nthcp);
\r
6991 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6992 if (*nthdir != NULLCHAR) {
\r
6993 q = QuoteForFilename(nthdir);
\r
6994 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6996 if (*nthcp == NULLCHAR) {
\r
6997 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6998 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6999 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7000 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7005 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7007 char buf[MSG_SIZ];
\r
7011 switch (message) {
\r
7012 case WM_INITDIALOG:
\r
7013 /* Center the dialog */
\r
7014 CenterWindow (hDlg, GetDesktopWindow());
\r
7015 /* Initialize the dialog items */
\r
7016 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7017 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7018 firstChessProgramNames);
\r
7019 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7020 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7021 secondChessProgramNames);
\r
7022 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7023 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7024 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7025 if (*appData.icsHelper != NULLCHAR) {
\r
7026 char *q = QuoteForFilename(appData.icsHelper);
\r
7027 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7029 if (*appData.icsHost == NULLCHAR) {
\r
7030 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7031 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7032 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7033 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7034 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7037 if (appData.icsActive) {
\r
7038 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7040 else if (appData.noChessProgram) {
\r
7041 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7044 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7047 SetStartupDialogEnables(hDlg);
\r
7051 switch (LOWORD(wParam)) {
\r
7053 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7054 strcpy(buf, "/fcp=");
\r
7055 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7057 ParseArgs(StringGet, &p);
\r
7058 strcpy(buf, "/scp=");
\r
7059 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7061 ParseArgs(StringGet, &p);
\r
7062 appData.noChessProgram = FALSE;
\r
7063 appData.icsActive = FALSE;
\r
7064 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7065 strcpy(buf, "/ics /icshost=");
\r
7066 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7068 ParseArgs(StringGet, &p);
\r
7069 if (appData.zippyPlay) {
\r
7070 strcpy(buf, "/fcp=");
\r
7071 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7073 ParseArgs(StringGet, &p);
\r
7075 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7076 appData.noChessProgram = TRUE;
\r
7077 appData.icsActive = FALSE;
\r
7079 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7080 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7083 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7084 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7086 ParseArgs(StringGet, &p);
\r
7088 EndDialog(hDlg, TRUE);
\r
7095 case IDM_HELPCONTENTS:
\r
7096 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7097 MessageBox (GetFocus(),
\r
7098 "Unable to activate help",
\r
7099 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7104 SetStartupDialogEnables(hDlg);
\r
7112 /*---------------------------------------------------------------------------*\
\r
7114 * About box dialog functions
\r
7116 \*---------------------------------------------------------------------------*/
\r
7118 /* Process messages for "About" dialog box */
\r
7120 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7122 switch (message) {
\r
7123 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7124 /* Center the dialog over the application window */
\r
7125 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7126 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7130 case WM_COMMAND: /* message: received a command */
\r
7131 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7132 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7133 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7141 /*---------------------------------------------------------------------------*\
\r
7143 * Comment Dialog functions
\r
7145 \*---------------------------------------------------------------------------*/
\r
7148 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7150 static HANDLE hwndText = NULL;
\r
7151 int len, newSizeX, newSizeY, flags;
\r
7152 static int sizeX, sizeY;
\r
7157 switch (message) {
\r
7158 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7159 /* Initialize the dialog items */
\r
7160 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7161 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7162 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7163 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7164 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7165 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7166 SetWindowText(hDlg, commentTitle);
\r
7167 if (editComment) {
\r
7168 SetFocus(hwndText);
\r
7170 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7172 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7173 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7174 MAKELPARAM(FALSE, 0));
\r
7175 /* Size and position the dialog */
\r
7176 if (!commentDialog) {
\r
7177 commentDialog = hDlg;
\r
7178 flags = SWP_NOZORDER;
\r
7179 GetClientRect(hDlg, &rect);
\r
7180 sizeX = rect.right;
\r
7181 sizeY = rect.bottom;
\r
7182 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7183 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7184 WINDOWPLACEMENT wp;
\r
7185 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7186 wp.length = sizeof(WINDOWPLACEMENT);
\r
7188 wp.showCmd = SW_SHOW;
\r
7189 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7190 wp.rcNormalPosition.left = commentX;
\r
7191 wp.rcNormalPosition.right = commentX + commentW;
\r
7192 wp.rcNormalPosition.top = commentY;
\r
7193 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7194 SetWindowPlacement(hDlg, &wp);
\r
7196 GetClientRect(hDlg, &rect);
\r
7197 newSizeX = rect.right;
\r
7198 newSizeY = rect.bottom;
\r
7199 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7200 newSizeX, newSizeY);
\r
7207 case WM_COMMAND: /* message: received a command */
\r
7208 switch (LOWORD(wParam)) {
\r
7210 if (editComment) {
\r
7212 /* Read changed options from the dialog box */
\r
7213 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7214 len = GetWindowTextLength(hwndText);
\r
7215 str = (char *) malloc(len + 1);
\r
7216 GetWindowText(hwndText, str, len + 1);
\r
7225 ReplaceComment(commentIndex, str);
\r
7232 case OPT_CancelComment:
\r
7236 case OPT_ClearComment:
\r
7237 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7240 case OPT_EditComment:
\r
7241 EditCommentEvent();
\r
7250 newSizeX = LOWORD(lParam);
\r
7251 newSizeY = HIWORD(lParam);
\r
7252 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7257 case WM_GETMINMAXINFO:
\r
7258 /* Prevent resizing window too small */
\r
7259 mmi = (MINMAXINFO *) lParam;
\r
7260 mmi->ptMinTrackSize.x = 100;
\r
7261 mmi->ptMinTrackSize.y = 100;
\r
7268 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7273 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7275 if (str == NULL) str = "";
\r
7276 p = (char *) malloc(2 * strlen(str) + 2);
\r
7279 if (*str == '\n') *q++ = '\r';
\r
7283 if (commentText != NULL) free(commentText);
\r
7285 commentIndex = index;
\r
7286 commentTitle = title;
\r
7288 editComment = edit;
\r
7290 if (commentDialog) {
\r
7291 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7292 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7294 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7295 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7296 hwndMain, (DLGPROC)lpProc);
\r
7297 FreeProcInstance(lpProc);
\r
7299 commentDialogUp = TRUE;
\r
7303 /*---------------------------------------------------------------------------*\
\r
7305 * Type-in move dialog functions
\r
7307 \*---------------------------------------------------------------------------*/
\r
7310 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7312 char move[MSG_SIZ];
\r
7314 ChessMove moveType;
\r
7315 int fromX, fromY, toX, toY;
\r
7318 switch (message) {
\r
7319 case WM_INITDIALOG:
\r
7320 move[0] = (char) lParam;
\r
7321 move[1] = NULLCHAR;
\r
7322 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7323 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7324 SetWindowText(hInput, move);
\r
7326 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7330 switch (LOWORD(wParam)) {
\r
7332 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7333 { int n; Board board;
\r
7335 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7336 EditPositionPasteFEN(move);
\r
7337 EndDialog(hDlg, TRUE);
\r
7340 // [HGM] movenum: allow move number to be typed in any mode
\r
7341 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7342 currentMove = 2*n-1;
\r
7343 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7344 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7345 EndDialog(hDlg, TRUE);
\r
7346 DrawPosition(TRUE, boards[currentMove]);
\r
7347 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7348 else DisplayMessage("", "");
\r
7352 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7353 gameMode != Training) {
\r
7354 DisplayMoveError("Displayed move is not current");
\r
7356 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7357 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7358 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7359 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7360 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7361 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7362 if (gameMode != Training)
\r
7363 forwardMostMove = currentMove;
\r
7364 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7366 DisplayMoveError("Could not parse move");
\r
7369 EndDialog(hDlg, TRUE);
\r
7372 EndDialog(hDlg, FALSE);
\r
7383 PopUpMoveDialog(char firstchar)
\r
7387 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7388 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7389 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7390 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7391 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7392 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7393 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7394 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7395 gameMode == Training) {
\r
7396 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7397 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7398 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7399 FreeProcInstance(lpProc);
\r
7403 /*---------------------------------------------------------------------------*\
\r
7405 * Type-in name dialog functions
\r
7407 \*---------------------------------------------------------------------------*/
\r
7410 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7412 char move[MSG_SIZ];
\r
7415 switch (message) {
\r
7416 case WM_INITDIALOG:
\r
7417 move[0] = (char) lParam;
\r
7418 move[1] = NULLCHAR;
\r
7419 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7420 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7421 SetWindowText(hInput, move);
\r
7423 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7427 switch (LOWORD(wParam)) {
\r
7429 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7430 appData.userName = strdup(move);
\r
7433 EndDialog(hDlg, TRUE);
\r
7436 EndDialog(hDlg, FALSE);
\r
7447 PopUpNameDialog(char firstchar)
\r
7451 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7452 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7453 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7454 FreeProcInstance(lpProc);
\r
7457 /*---------------------------------------------------------------------------*\
\r
7461 \*---------------------------------------------------------------------------*/
\r
7463 /* Nonmodal error box */
\r
7464 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7465 WPARAM wParam, LPARAM lParam);
\r
7468 ErrorPopUp(char *title, char *content)
\r
7472 BOOLEAN modal = hwndMain == NULL;
\r
7490 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7491 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7494 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7496 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7497 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7498 hwndMain, (DLGPROC)lpProc);
\r
7499 FreeProcInstance(lpProc);
\r
7506 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7507 if (errorDialog == NULL) return;
\r
7508 DestroyWindow(errorDialog);
\r
7509 errorDialog = NULL;
\r
7513 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7518 switch (message) {
\r
7519 case WM_INITDIALOG:
\r
7520 GetWindowRect(hDlg, &rChild);
\r
7523 SetWindowPos(hDlg, NULL, rChild.left,
\r
7524 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7525 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7529 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7530 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7531 and it doesn't work when you resize the dialog.
\r
7532 For now, just give it a default position.
\r
7534 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7536 errorDialog = hDlg;
\r
7537 SetWindowText(hDlg, errorTitle);
\r
7538 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7539 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7543 switch (LOWORD(wParam)) {
\r
7546 if (errorDialog == hDlg) errorDialog = NULL;
\r
7547 DestroyWindow(hDlg);
\r
7559 HWND gothicDialog = NULL;
\r
7562 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7566 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7568 switch (message) {
\r
7569 case WM_INITDIALOG:
\r
7570 GetWindowRect(hDlg, &rChild);
\r
7572 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7576 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7577 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7578 and it doesn't work when you resize the dialog.
\r
7579 For now, just give it a default position.
\r
7581 gothicDialog = hDlg;
\r
7582 SetWindowText(hDlg, errorTitle);
\r
7583 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7584 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7588 switch (LOWORD(wParam)) {
\r
7591 if (errorDialog == hDlg) errorDialog = NULL;
\r
7592 DestroyWindow(hDlg);
\r
7604 GothicPopUp(char *title, VariantClass variant)
\r
7607 static char *lastTitle;
\r
7609 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7610 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7612 if(lastTitle != title && gothicDialog != NULL) {
\r
7613 DestroyWindow(gothicDialog);
\r
7614 gothicDialog = NULL;
\r
7616 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7617 title = lastTitle;
\r
7618 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7619 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7620 hwndMain, (DLGPROC)lpProc);
\r
7621 FreeProcInstance(lpProc);
\r
7626 /*---------------------------------------------------------------------------*\
\r
7628 * Ics Interaction console functions
\r
7630 \*---------------------------------------------------------------------------*/
\r
7632 #define HISTORY_SIZE 64
\r
7633 static char *history[HISTORY_SIZE];
\r
7634 int histIn = 0, histP = 0;
\r
7637 SaveInHistory(char *cmd)
\r
7639 if (history[histIn] != NULL) {
\r
7640 free(history[histIn]);
\r
7641 history[histIn] = NULL;
\r
7643 if (*cmd == NULLCHAR) return;
\r
7644 history[histIn] = StrSave(cmd);
\r
7645 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7646 if (history[histIn] != NULL) {
\r
7647 free(history[histIn]);
\r
7648 history[histIn] = NULL;
\r
7654 PrevInHistory(char *cmd)
\r
7657 if (histP == histIn) {
\r
7658 if (history[histIn] != NULL) free(history[histIn]);
\r
7659 history[histIn] = StrSave(cmd);
\r
7661 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7662 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7664 return history[histP];
\r
7670 if (histP == histIn) return NULL;
\r
7671 histP = (histP + 1) % HISTORY_SIZE;
\r
7672 return history[histP];
\r
7679 BOOLEAN immediate;
\r
7680 } IcsTextMenuEntry;
\r
7681 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7682 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7685 ParseIcsTextMenu(char *icsTextMenuString)
\r
7688 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7689 char *p = icsTextMenuString;
\r
7690 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7693 if (e->command != NULL) {
\r
7695 e->command = NULL;
\r
7699 e = icsTextMenuEntry;
\r
7700 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7701 if (*p == ';' || *p == '\n') {
\r
7702 e->item = strdup("-");
\r
7703 e->command = NULL;
\r
7705 } else if (*p == '-') {
\r
7706 e->item = strdup("-");
\r
7707 e->command = NULL;
\r
7711 char *q, *r, *s, *t;
\r
7713 q = strchr(p, ',');
\r
7714 if (q == NULL) break;
\r
7716 r = strchr(q + 1, ',');
\r
7717 if (r == NULL) break;
\r
7719 s = strchr(r + 1, ',');
\r
7720 if (s == NULL) break;
\r
7723 t = strchr(s + 1, c);
\r
7726 t = strchr(s + 1, c);
\r
7728 if (t != NULL) *t = NULLCHAR;
\r
7729 e->item = strdup(p);
\r
7730 e->command = strdup(q + 1);
\r
7731 e->getname = *(r + 1) != '0';
\r
7732 e->immediate = *(s + 1) != '0';
\r
7736 if (t == NULL) break;
\r
7745 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7749 hmenu = LoadMenu(hInst, "TextMenu");
\r
7750 h = GetSubMenu(hmenu, 0);
\r
7752 if (strcmp(e->item, "-") == 0) {
\r
7753 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7755 if (e->item[0] == '|') {
\r
7756 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7757 IDM_CommandX + i, &e->item[1]);
\r
7759 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7768 WNDPROC consoleTextWindowProc;
\r
7771 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7773 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7774 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7778 SetWindowText(hInput, command);
\r
7780 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7782 sel.cpMin = 999999;
\r
7783 sel.cpMax = 999999;
\r
7784 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7789 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7790 if (sel.cpMin == sel.cpMax) {
\r
7791 /* Expand to surrounding word */
\r
7794 tr.chrg.cpMax = sel.cpMin;
\r
7795 tr.chrg.cpMin = --sel.cpMin;
\r
7796 if (sel.cpMin < 0) break;
\r
7797 tr.lpstrText = name;
\r
7798 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7799 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7803 tr.chrg.cpMin = sel.cpMax;
\r
7804 tr.chrg.cpMax = ++sel.cpMax;
\r
7805 tr.lpstrText = name;
\r
7806 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7807 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7810 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7811 MessageBeep(MB_ICONEXCLAMATION);
\r
7815 tr.lpstrText = name;
\r
7816 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7818 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7819 MessageBeep(MB_ICONEXCLAMATION);
\r
7822 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7825 sprintf(buf, "%s %s", command, name);
\r
7826 SetWindowText(hInput, buf);
\r
7827 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7829 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7830 SetWindowText(hInput, buf);
\r
7831 sel.cpMin = 999999;
\r
7832 sel.cpMax = 999999;
\r
7833 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7839 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7844 switch (message) {
\r
7846 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7849 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7852 sel.cpMin = 999999;
\r
7853 sel.cpMax = 999999;
\r
7854 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7855 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7860 if(wParam != '\022') {
\r
7861 if (wParam == '\t') {
\r
7862 if (GetKeyState(VK_SHIFT) < 0) {
\r
7864 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7865 if (buttonDesc[0].hwnd) {
\r
7866 SetFocus(buttonDesc[0].hwnd);
\r
7868 SetFocus(hwndMain);
\r
7872 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7875 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7876 JAWS_DELETE( SetFocus(hInput); )
\r
7877 SendMessage(hInput, message, wParam, lParam);
\r
7880 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7881 case WM_RBUTTONUP:
\r
7882 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7883 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7884 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7887 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7888 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7889 if (sel.cpMin == sel.cpMax) {
\r
7890 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7891 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7893 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7894 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7896 pt.x = LOWORD(lParam);
\r
7897 pt.y = HIWORD(lParam);
\r
7898 MenuPopup(hwnd, pt, hmenu, -1);
\r
7902 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7904 return SendMessage(hInput, message, wParam, lParam);
\r
7905 case WM_MBUTTONDOWN:
\r
7906 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7907 case WM_RBUTTONDOWN:
\r
7908 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7909 /* Move selection here if it was empty */
\r
7911 pt.x = LOWORD(lParam);
\r
7912 pt.y = HIWORD(lParam);
\r
7913 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7914 if (sel.cpMin == sel.cpMax) {
\r
7915 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7916 sel.cpMax = sel.cpMin;
\r
7917 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7919 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7923 switch (LOWORD(wParam)) {
\r
7924 case IDM_QuickPaste:
\r
7926 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7927 if (sel.cpMin == sel.cpMax) {
\r
7928 MessageBeep(MB_ICONEXCLAMATION);
\r
7931 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7932 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7933 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7938 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7941 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7944 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7948 int i = LOWORD(wParam) - IDM_CommandX;
\r
7949 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7950 icsTextMenuEntry[i].command != NULL) {
\r
7951 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7952 icsTextMenuEntry[i].getname,
\r
7953 icsTextMenuEntry[i].immediate);
\r
7961 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7964 WNDPROC consoleInputWindowProc;
\r
7967 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7969 char buf[MSG_SIZ];
\r
7971 static BOOL sendNextChar = FALSE;
\r
7972 static BOOL quoteNextChar = FALSE;
\r
7973 InputSource *is = consoleInputSource;
\r
7977 switch (message) {
\r
7979 if (!appData.localLineEditing || sendNextChar) {
\r
7980 is->buf[0] = (CHAR) wParam;
\r
7982 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7983 sendNextChar = FALSE;
\r
7986 if (quoteNextChar) {
\r
7987 buf[0] = (char) wParam;
\r
7988 buf[1] = NULLCHAR;
\r
7989 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7990 quoteNextChar = FALSE;
\r
7994 case '\r': /* Enter key */
\r
7995 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7996 if (consoleEcho) SaveInHistory(is->buf);
\r
7997 is->buf[is->count++] = '\n';
\r
7998 is->buf[is->count] = NULLCHAR;
\r
7999 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8000 if (consoleEcho) {
\r
8001 ConsoleOutput(is->buf, is->count, TRUE);
\r
8002 } else if (appData.localLineEditing) {
\r
8003 ConsoleOutput("\n", 1, TRUE);
\r
8006 case '\033': /* Escape key */
\r
8007 SetWindowText(hwnd, "");
\r
8008 cf.cbSize = sizeof(CHARFORMAT);
\r
8009 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8010 if (consoleEcho) {
\r
8011 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8013 cf.crTextColor = COLOR_ECHOOFF;
\r
8015 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8016 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8018 case '\t': /* Tab key */
\r
8019 if (GetKeyState(VK_SHIFT) < 0) {
\r
8021 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8024 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8025 if (buttonDesc[0].hwnd) {
\r
8026 SetFocus(buttonDesc[0].hwnd);
\r
8028 SetFocus(hwndMain);
\r
8032 case '\023': /* Ctrl+S */
\r
8033 sendNextChar = TRUE;
\r
8035 case '\021': /* Ctrl+Q */
\r
8036 quoteNextChar = TRUE;
\r
8046 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8047 p = PrevInHistory(buf);
\r
8049 SetWindowText(hwnd, p);
\r
8050 sel.cpMin = 999999;
\r
8051 sel.cpMax = 999999;
\r
8052 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8057 p = NextInHistory();
\r
8059 SetWindowText(hwnd, p);
\r
8060 sel.cpMin = 999999;
\r
8061 sel.cpMax = 999999;
\r
8062 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8068 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8072 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8076 case WM_MBUTTONDOWN:
\r
8077 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8078 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8080 case WM_RBUTTONUP:
\r
8081 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8082 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8083 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8087 hmenu = LoadMenu(hInst, "InputMenu");
\r
8088 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8089 if (sel.cpMin == sel.cpMax) {
\r
8090 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8091 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8093 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8094 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8096 pt.x = LOWORD(lParam);
\r
8097 pt.y = HIWORD(lParam);
\r
8098 MenuPopup(hwnd, pt, hmenu, -1);
\r
8102 switch (LOWORD(wParam)) {
\r
8104 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8106 case IDM_SelectAll:
\r
8108 sel.cpMax = -1; /*999999?*/
\r
8109 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8112 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8115 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8118 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8123 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8126 #define CO_MAX 100000
\r
8127 #define CO_TRIM 1000
\r
8130 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8132 static SnapData sd;
\r
8133 HWND hText, hInput;
\r
8135 static int sizeX, sizeY;
\r
8136 int newSizeX, newSizeY;
\r
8140 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8141 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8143 switch (message) {
\r
8145 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8147 ENLINK *pLink = (ENLINK*)lParam;
\r
8148 if (pLink->msg == WM_LBUTTONUP)
\r
8152 tr.chrg = pLink->chrg;
\r
8153 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8154 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8155 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8156 free(tr.lpstrText);
\r
8160 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8161 hwndConsole = hDlg;
\r
8163 consoleTextWindowProc = (WNDPROC)
\r
8164 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8165 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8166 consoleInputWindowProc = (WNDPROC)
\r
8167 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8168 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8169 Colorize(ColorNormal, TRUE);
\r
8170 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8171 ChangedConsoleFont();
\r
8172 GetClientRect(hDlg, &rect);
\r
8173 sizeX = rect.right;
\r
8174 sizeY = rect.bottom;
\r
8175 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8176 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8177 WINDOWPLACEMENT wp;
\r
8178 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8179 wp.length = sizeof(WINDOWPLACEMENT);
\r
8181 wp.showCmd = SW_SHOW;
\r
8182 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8183 wp.rcNormalPosition.left = wpConsole.x;
\r
8184 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8185 wp.rcNormalPosition.top = wpConsole.y;
\r
8186 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8187 SetWindowPlacement(hDlg, &wp);
\r
8190 // [HGM] Chessknight's change 2004-07-13
\r
8191 else { /* Determine Defaults */
\r
8192 WINDOWPLACEMENT wp;
\r
8193 wpConsole.x = winWidth + 1;
\r
8194 wpConsole.y = boardY;
\r
8195 wpConsole.width = screenWidth - winWidth;
\r
8196 wpConsole.height = winHeight;
\r
8197 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8198 wp.length = sizeof(WINDOWPLACEMENT);
\r
8200 wp.showCmd = SW_SHOW;
\r
8201 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8202 wp.rcNormalPosition.left = wpConsole.x;
\r
8203 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8204 wp.rcNormalPosition.top = wpConsole.y;
\r
8205 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8206 SetWindowPlacement(hDlg, &wp);
\r
8209 // Allow hText to highlight URLs and send notifications on them
\r
8210 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8211 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8212 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8213 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8227 if (IsIconic(hDlg)) break;
\r
8228 newSizeX = LOWORD(lParam);
\r
8229 newSizeY = HIWORD(lParam);
\r
8230 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8231 RECT rectText, rectInput;
\r
8233 int newTextHeight, newTextWidth;
\r
8234 GetWindowRect(hText, &rectText);
\r
8235 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8236 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8237 if (newTextHeight < 0) {
\r
8238 newSizeY += -newTextHeight;
\r
8239 newTextHeight = 0;
\r
8241 SetWindowPos(hText, NULL, 0, 0,
\r
8242 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8243 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8244 pt.x = rectInput.left;
\r
8245 pt.y = rectInput.top + newSizeY - sizeY;
\r
8246 ScreenToClient(hDlg, &pt);
\r
8247 SetWindowPos(hInput, NULL,
\r
8248 pt.x, pt.y, /* needs client coords */
\r
8249 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8250 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8256 case WM_GETMINMAXINFO:
\r
8257 /* Prevent resizing window too small */
\r
8258 mmi = (MINMAXINFO *) lParam;
\r
8259 mmi->ptMinTrackSize.x = 100;
\r
8260 mmi->ptMinTrackSize.y = 100;
\r
8263 /* [AS] Snapping */
\r
8264 case WM_ENTERSIZEMOVE:
\r
8265 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8268 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8271 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8273 case WM_EXITSIZEMOVE:
\r
8274 UpdateICSWidth(hText);
\r
8275 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8278 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8286 if (hwndConsole) return;
\r
8287 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8288 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8293 ConsoleOutput(char* data, int length, int forceVisible)
\r
8298 char buf[CO_MAX+1];
\r
8301 static int delayLF = 0;
\r
8302 CHARRANGE savesel, sel;
\r
8304 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8312 while (length--) {
\r
8320 } else if (*p == '\007') {
\r
8321 MyPlaySound(&sounds[(int)SoundBell]);
\r
8328 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8329 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8330 /* Save current selection */
\r
8331 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8332 exlen = GetWindowTextLength(hText);
\r
8333 /* Find out whether current end of text is visible */
\r
8334 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8335 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8336 /* Trim existing text if it's too long */
\r
8337 if (exlen + (q - buf) > CO_MAX) {
\r
8338 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8341 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8342 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8344 savesel.cpMin -= trim;
\r
8345 savesel.cpMax -= trim;
\r
8346 if (exlen < 0) exlen = 0;
\r
8347 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8348 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8350 /* Append the new text */
\r
8351 sel.cpMin = exlen;
\r
8352 sel.cpMax = exlen;
\r
8353 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8354 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8355 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8356 if (forceVisible || exlen == 0 ||
\r
8357 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8358 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8359 /* Scroll to make new end of text visible if old end of text
\r
8360 was visible or new text is an echo of user typein */
\r
8361 sel.cpMin = 9999999;
\r
8362 sel.cpMax = 9999999;
\r
8363 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8364 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8365 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8366 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8368 if (savesel.cpMax == exlen || forceVisible) {
\r
8369 /* Move insert point to new end of text if it was at the old
\r
8370 end of text or if the new text is an echo of user typein */
\r
8371 sel.cpMin = 9999999;
\r
8372 sel.cpMax = 9999999;
\r
8373 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8375 /* Restore previous selection */
\r
8376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8378 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8385 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8389 COLORREF oldFg, oldBg;
\r
8393 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8395 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8396 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8397 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8400 rect.right = x + squareSize;
\r
8402 rect.bottom = y + squareSize;
\r
8405 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8406 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8407 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8408 &rect, str, strlen(str), NULL);
\r
8410 (void) SetTextColor(hdc, oldFg);
\r
8411 (void) SetBkColor(hdc, oldBg);
\r
8412 (void) SelectObject(hdc, oldFont);
\r
8416 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8417 RECT *rect, char *color, char *flagFell)
\r
8421 COLORREF oldFg, oldBg;
\r
8424 if (appData.clockMode) {
\r
8426 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8428 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8435 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8436 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8438 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8439 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8441 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8445 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8446 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8447 rect, str, strlen(str), NULL);
\r
8448 if(logoHeight > 0 && appData.clockMode) {
\r
8450 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8451 r.top = rect->top + logoHeight/2;
\r
8452 r.left = rect->left;
\r
8453 r.right = rect->right;
\r
8454 r.bottom = rect->bottom;
\r
8455 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8456 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8457 &r, str, strlen(str), NULL);
\r
8459 (void) SetTextColor(hdc, oldFg);
\r
8460 (void) SetBkColor(hdc, oldBg);
\r
8461 (void) SelectObject(hdc, oldFont);
\r
8466 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8472 if( count <= 0 ) {
\r
8473 if (appData.debugMode) {
\r
8474 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8477 return ERROR_INVALID_USER_BUFFER;
\r
8480 ResetEvent(ovl->hEvent);
\r
8481 ovl->Offset = ovl->OffsetHigh = 0;
\r
8482 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8486 err = GetLastError();
\r
8487 if (err == ERROR_IO_PENDING) {
\r
8488 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8492 err = GetLastError();
\r
8499 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8504 ResetEvent(ovl->hEvent);
\r
8505 ovl->Offset = ovl->OffsetHigh = 0;
\r
8506 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8510 err = GetLastError();
\r
8511 if (err == ERROR_IO_PENDING) {
\r
8512 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8516 err = GetLastError();
\r
8522 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8523 void CheckForInputBufferFull( InputSource * is )
\r
8525 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8526 /* Look for end of line */
\r
8527 char * p = is->buf;
\r
8529 while( p < is->next && *p != '\n' ) {
\r
8533 if( p >= is->next ) {
\r
8534 if (appData.debugMode) {
\r
8535 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8538 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8539 is->count = (DWORD) -1;
\r
8540 is->next = is->buf;
\r
8546 InputThread(LPVOID arg)
\r
8551 is = (InputSource *) arg;
\r
8552 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8553 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8554 while (is->hThread != NULL) {
\r
8555 is->error = DoReadFile(is->hFile, is->next,
\r
8556 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8557 &is->count, &ovl);
\r
8558 if (is->error == NO_ERROR) {
\r
8559 is->next += is->count;
\r
8561 if (is->error == ERROR_BROKEN_PIPE) {
\r
8562 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8565 is->count = (DWORD) -1;
\r
8566 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8571 CheckForInputBufferFull( is );
\r
8573 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8575 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8577 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8580 CloseHandle(ovl.hEvent);
\r
8581 CloseHandle(is->hFile);
\r
8583 if (appData.debugMode) {
\r
8584 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8591 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8593 NonOvlInputThread(LPVOID arg)
\r
8600 is = (InputSource *) arg;
\r
8601 while (is->hThread != NULL) {
\r
8602 is->error = ReadFile(is->hFile, is->next,
\r
8603 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8604 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8605 if (is->error == NO_ERROR) {
\r
8606 /* Change CRLF to LF */
\r
8607 if (is->next > is->buf) {
\r
8609 i = is->count + 1;
\r
8617 if (prev == '\r' && *p == '\n') {
\r
8629 if (is->error == ERROR_BROKEN_PIPE) {
\r
8630 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8633 is->count = (DWORD) -1;
\r
8637 CheckForInputBufferFull( is );
\r
8639 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8641 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8643 if (is->count < 0) break; /* Quit on error */
\r
8645 CloseHandle(is->hFile);
\r
8650 SocketInputThread(LPVOID arg)
\r
8654 is = (InputSource *) arg;
\r
8655 while (is->hThread != NULL) {
\r
8656 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8657 if ((int)is->count == SOCKET_ERROR) {
\r
8658 is->count = (DWORD) -1;
\r
8659 is->error = WSAGetLastError();
\r
8661 is->error = NO_ERROR;
\r
8662 is->next += is->count;
\r
8663 if (is->count == 0 && is->second == is) {
\r
8664 /* End of file on stderr; quit with no message */
\r
8668 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8670 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8672 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8678 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8682 is = (InputSource *) lParam;
\r
8683 if (is->lineByLine) {
\r
8684 /* Feed in lines one by one */
\r
8685 char *p = is->buf;
\r
8687 while (q < is->next) {
\r
8688 if (*q++ == '\n') {
\r
8689 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8694 /* Move any partial line to the start of the buffer */
\r
8696 while (p < is->next) {
\r
8701 if (is->error != NO_ERROR || is->count == 0) {
\r
8702 /* Notify backend of the error. Note: If there was a partial
\r
8703 line at the end, it is not flushed through. */
\r
8704 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8707 /* Feed in the whole chunk of input at once */
\r
8708 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8709 is->next = is->buf;
\r
8713 /*---------------------------------------------------------------------------*\
\r
8715 * Menu enables. Used when setting various modes.
\r
8717 \*---------------------------------------------------------------------------*/
\r
8725 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8727 while (enab->item > 0) {
\r
8728 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8733 Enables gnuEnables[] = {
\r
8734 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8735 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8736 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8737 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8738 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8739 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8740 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8742 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8747 Enables icsEnables[] = {
\r
8748 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8754 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8764 Enables zippyEnables[] = {
\r
8765 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8766 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8767 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8772 Enables ncpEnables[] = {
\r
8773 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8774 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8782 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8791 Enables trainingOnEnables[] = {
\r
8792 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8803 Enables trainingOffEnables[] = {
\r
8804 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8805 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8806 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8807 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8808 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8809 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8810 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8811 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8815 /* These modify either ncpEnables or gnuEnables */
\r
8816 Enables cmailEnables[] = {
\r
8817 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8819 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8820 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8822 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8827 Enables machineThinkingEnables[] = {
\r
8828 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8846 Enables userThinkingEnables[] = {
\r
8847 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8853 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8854 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8855 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8865 /*---------------------------------------------------------------------------*\
\r
8867 * Front-end interface functions exported by XBoard.
\r
8868 * Functions appear in same order as prototypes in frontend.h.
\r
8870 \*---------------------------------------------------------------------------*/
\r
8874 static UINT prevChecked = 0;
\r
8875 static int prevPausing = 0;
\r
8878 if (pausing != prevPausing) {
\r
8879 prevPausing = pausing;
\r
8880 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8881 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8882 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8885 switch (gameMode) {
\r
8886 case BeginningOfGame:
\r
8887 if (appData.icsActive)
\r
8888 nowChecked = IDM_IcsClient;
\r
8889 else if (appData.noChessProgram)
\r
8890 nowChecked = IDM_EditGame;
\r
8892 nowChecked = IDM_MachineBlack;
\r
8894 case MachinePlaysBlack:
\r
8895 nowChecked = IDM_MachineBlack;
\r
8897 case MachinePlaysWhite:
\r
8898 nowChecked = IDM_MachineWhite;
\r
8900 case TwoMachinesPlay:
\r
8901 nowChecked = IDM_TwoMachines;
\r
8904 nowChecked = IDM_AnalysisMode;
\r
8907 nowChecked = IDM_AnalyzeFile;
\r
8910 nowChecked = IDM_EditGame;
\r
8912 case PlayFromGameFile:
\r
8913 nowChecked = IDM_LoadGame;
\r
8915 case EditPosition:
\r
8916 nowChecked = IDM_EditPosition;
\r
8919 nowChecked = IDM_Training;
\r
8921 case IcsPlayingWhite:
\r
8922 case IcsPlayingBlack:
\r
8923 case IcsObserving:
\r
8925 nowChecked = IDM_IcsClient;
\r
8932 if (prevChecked != 0)
\r
8933 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8934 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8935 if (nowChecked != 0)
\r
8936 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8937 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8939 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8940 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8941 MF_BYCOMMAND|MF_ENABLED);
\r
8943 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8944 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8947 prevChecked = nowChecked;
\r
8949 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8950 if (appData.icsActive) {
\r
8951 if (appData.icsEngineAnalyze) {
\r
8952 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8953 MF_BYCOMMAND|MF_CHECKED);
\r
8955 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8956 MF_BYCOMMAND|MF_UNCHECKED);
\r
8964 HMENU hmenu = GetMenu(hwndMain);
\r
8965 SetMenuEnables(hmenu, icsEnables);
\r
8966 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8967 MF_BYPOSITION|MF_ENABLED);
\r
8969 if (appData.zippyPlay) {
\r
8970 SetMenuEnables(hmenu, zippyEnables);
\r
8971 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8972 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8973 MF_BYCOMMAND|MF_ENABLED);
\r
8981 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8987 HMENU hmenu = GetMenu(hwndMain);
\r
8988 SetMenuEnables(hmenu, ncpEnables);
\r
8989 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8990 MF_BYPOSITION|MF_GRAYED);
\r
8991 DrawMenuBar(hwndMain);
\r
8997 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9001 SetTrainingModeOn()
\r
9004 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9005 for (i = 0; i < N_BUTTONS; i++) {
\r
9006 if (buttonDesc[i].hwnd != NULL)
\r
9007 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9012 VOID SetTrainingModeOff()
\r
9015 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9016 for (i = 0; i < N_BUTTONS; i++) {
\r
9017 if (buttonDesc[i].hwnd != NULL)
\r
9018 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9024 SetUserThinkingEnables()
\r
9026 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9030 SetMachineThinkingEnables()
\r
9032 HMENU hMenu = GetMenu(hwndMain);
\r
9033 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9035 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9037 if (gameMode == MachinePlaysBlack) {
\r
9038 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9039 } else if (gameMode == MachinePlaysWhite) {
\r
9040 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9041 } else if (gameMode == TwoMachinesPlay) {
\r
9042 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9048 DisplayTitle(char *str)
\r
9050 char title[MSG_SIZ], *host;
\r
9051 if (str[0] != NULLCHAR) {
\r
9052 strcpy(title, str);
\r
9053 } else if (appData.icsActive) {
\r
9054 if (appData.icsCommPort[0] != NULLCHAR)
\r
9057 host = appData.icsHost;
\r
9058 sprintf(title, "%s: %s", szTitle, host);
\r
9059 } else if (appData.noChessProgram) {
\r
9060 strcpy(title, szTitle);
\r
9062 strcpy(title, szTitle);
\r
9063 strcat(title, ": ");
\r
9064 strcat(title, first.tidy);
\r
9066 SetWindowText(hwndMain, title);
\r
9071 DisplayMessage(char *str1, char *str2)
\r
9075 int remain = MESSAGE_TEXT_MAX - 1;
\r
9078 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9079 messageText[0] = NULLCHAR;
\r
9081 len = strlen(str1);
\r
9082 if (len > remain) len = remain;
\r
9083 strncpy(messageText, str1, len);
\r
9084 messageText[len] = NULLCHAR;
\r
9087 if (*str2 && remain >= 2) {
\r
9089 strcat(messageText, " ");
\r
9092 len = strlen(str2);
\r
9093 if (len > remain) len = remain;
\r
9094 strncat(messageText, str2, len);
\r
9096 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9098 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9102 hdc = GetDC(hwndMain);
\r
9103 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9104 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9105 &messageRect, messageText, strlen(messageText), NULL);
\r
9106 (void) SelectObject(hdc, oldFont);
\r
9107 (void) ReleaseDC(hwndMain, hdc);
\r
9111 DisplayError(char *str, int error)
\r
9113 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9119 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9120 NULL, error, LANG_NEUTRAL,
\r
9121 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9123 sprintf(buf, "%s:\n%s", str, buf2);
\r
9125 ErrorMap *em = errmap;
\r
9126 while (em->err != 0 && em->err != error) em++;
\r
9127 if (em->err != 0) {
\r
9128 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9130 sprintf(buf, "%s:\nError code %d", str, error);
\r
9135 ErrorPopUp("Error", buf);
\r
9140 DisplayMoveError(char *str)
\r
9142 fromX = fromY = -1;
\r
9143 ClearHighlights();
\r
9144 DrawPosition(FALSE, NULL);
\r
9145 if (appData.popupMoveErrors) {
\r
9146 ErrorPopUp("Error", str);
\r
9148 DisplayMessage(str, "");
\r
9149 moveErrorMessageUp = TRUE;
\r
9154 DisplayFatalError(char *str, int error, int exitStatus)
\r
9156 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9158 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9161 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9162 NULL, error, LANG_NEUTRAL,
\r
9163 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9165 sprintf(buf, "%s:\n%s", str, buf2);
\r
9167 ErrorMap *em = errmap;
\r
9168 while (em->err != 0 && em->err != error) em++;
\r
9169 if (em->err != 0) {
\r
9170 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9172 sprintf(buf, "%s:\nError code %d", str, error);
\r
9177 if (appData.debugMode) {
\r
9178 fprintf(debugFP, "%s: %s\n", label, str);
\r
9180 if (appData.popupExitMessage) {
\r
9181 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9182 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9184 ExitEvent(exitStatus);
\r
9189 DisplayInformation(char *str)
\r
9191 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9196 DisplayNote(char *str)
\r
9198 ErrorPopUp("Note", str);
\r
9203 char *title, *question, *replyPrefix;
\r
9208 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9210 static QuestionParams *qp;
\r
9211 char reply[MSG_SIZ];
\r
9214 switch (message) {
\r
9215 case WM_INITDIALOG:
\r
9216 qp = (QuestionParams *) lParam;
\r
9217 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9218 SetWindowText(hDlg, qp->title);
\r
9219 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9220 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9224 switch (LOWORD(wParam)) {
\r
9226 strcpy(reply, qp->replyPrefix);
\r
9227 if (*reply) strcat(reply, " ");
\r
9228 len = strlen(reply);
\r
9229 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9230 strcat(reply, "\n");
\r
9231 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9232 EndDialog(hDlg, TRUE);
\r
9233 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9236 EndDialog(hDlg, FALSE);
\r
9247 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9249 QuestionParams qp;
\r
9253 qp.question = question;
\r
9254 qp.replyPrefix = replyPrefix;
\r
9256 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9257 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9258 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9259 FreeProcInstance(lpProc);
\r
9262 /* [AS] Pick FRC position */
\r
9263 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9265 static int * lpIndexFRC;
\r
9271 case WM_INITDIALOG:
\r
9272 lpIndexFRC = (int *) lParam;
\r
9274 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9276 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9277 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9278 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9279 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9284 switch( LOWORD(wParam) ) {
\r
9286 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9287 EndDialog( hDlg, 0 );
\r
9288 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9291 EndDialog( hDlg, 1 );
\r
9293 case IDC_NFG_Edit:
\r
9294 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9295 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9297 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9300 case IDC_NFG_Random:
\r
9301 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9302 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9315 int index = appData.defaultFrcPosition;
\r
9316 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9318 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9320 if( result == 0 ) {
\r
9321 appData.defaultFrcPosition = index;
\r
9327 /* [AS] Game list options */
\r
9333 static GLT_Item GLT_ItemInfo[] = {
\r
9334 { GLT_EVENT, "Event" },
\r
9335 { GLT_SITE, "Site" },
\r
9336 { GLT_DATE, "Date" },
\r
9337 { GLT_ROUND, "Round" },
\r
9338 { GLT_PLAYERS, "Players" },
\r
9339 { GLT_RESULT, "Result" },
\r
9340 { GLT_WHITE_ELO, "White Rating" },
\r
9341 { GLT_BLACK_ELO, "Black Rating" },
\r
9342 { GLT_TIME_CONTROL,"Time Control" },
\r
9343 { GLT_VARIANT, "Variant" },
\r
9344 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9345 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9349 const char * GLT_FindItem( char id )
\r
9351 const char * result = 0;
\r
9353 GLT_Item * list = GLT_ItemInfo;
\r
9355 while( list->id != 0 ) {
\r
9356 if( list->id == id ) {
\r
9357 result = list->name;
\r
9367 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9369 const char * name = GLT_FindItem( id );
\r
9372 if( index >= 0 ) {
\r
9373 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9376 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9381 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9385 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9388 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9392 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9394 pc = GLT_ALL_TAGS;
\r
9397 if( strchr( tags, *pc ) == 0 ) {
\r
9398 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9403 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9406 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9408 char result = '\0';
\r
9411 GLT_Item * list = GLT_ItemInfo;
\r
9413 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9414 while( list->id != 0 ) {
\r
9415 if( strcmp( list->name, name ) == 0 ) {
\r
9416 result = list->id;
\r
9427 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9429 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9430 int idx2 = idx1 + delta;
\r
9431 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9433 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9436 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9437 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9438 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9439 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9443 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9445 static char glt[64];
\r
9446 static char * lpUserGLT;
\r
9450 case WM_INITDIALOG:
\r
9451 lpUserGLT = (char *) lParam;
\r
9453 strcpy( glt, lpUserGLT );
\r
9455 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9457 /* Initialize list */
\r
9458 GLT_TagsToList( hDlg, glt );
\r
9460 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9465 switch( LOWORD(wParam) ) {
\r
9468 char * pc = lpUserGLT;
\r
9470 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9474 id = GLT_ListItemToTag( hDlg, idx );
\r
9478 } while( id != '\0' );
\r
9480 EndDialog( hDlg, 0 );
\r
9483 EndDialog( hDlg, 1 );
\r
9486 case IDC_GLT_Default:
\r
9487 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9488 GLT_TagsToList( hDlg, glt );
\r
9491 case IDC_GLT_Restore:
\r
9492 strcpy( glt, lpUserGLT );
\r
9493 GLT_TagsToList( hDlg, glt );
\r
9497 GLT_MoveSelection( hDlg, -1 );
\r
9500 case IDC_GLT_Down:
\r
9501 GLT_MoveSelection( hDlg, +1 );
\r
9511 int GameListOptions()
\r
9515 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9517 strcpy( glt, appData.gameListTags );
\r
9519 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9521 if( result == 0 ) {
\r
9522 /* [AS] Memory leak here! */
\r
9523 appData.gameListTags = strdup( glt );
\r
9531 DisplayIcsInteractionTitle(char *str)
\r
9533 char consoleTitle[MSG_SIZ];
\r
9535 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9536 SetWindowText(hwndConsole, consoleTitle);
\r
9540 DrawPosition(int fullRedraw, Board board)
\r
9542 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9545 void NotifyFrontendLogin()
\r
9548 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9554 fromX = fromY = -1;
\r
9555 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9556 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9557 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9558 dragInfo.lastpos = dragInfo.pos;
\r
9559 dragInfo.start.x = dragInfo.start.y = -1;
\r
9560 dragInfo.from = dragInfo.start;
\r
9562 DrawPosition(TRUE, NULL);
\r
9568 CommentPopUp(char *title, char *str)
\r
9570 HWND hwnd = GetActiveWindow();
\r
9571 EitherCommentPopUp(0, title, str, FALSE);
\r
9573 SetActiveWindow(hwnd);
\r
9577 CommentPopDown(void)
\r
9579 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9580 if (commentDialog) {
\r
9581 ShowWindow(commentDialog, SW_HIDE);
\r
9583 commentDialogUp = FALSE;
\r
9587 EditCommentPopUp(int index, char *title, char *str)
\r
9589 EitherCommentPopUp(index, title, str, TRUE);
\r
9596 MyPlaySound(&sounds[(int)SoundMove]);
\r
9599 VOID PlayIcsWinSound()
\r
9601 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9604 VOID PlayIcsLossSound()
\r
9606 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9609 VOID PlayIcsDrawSound()
\r
9611 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9614 VOID PlayIcsUnfinishedSound()
\r
9616 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9622 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9630 consoleEcho = TRUE;
\r
9631 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9632 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9633 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9642 consoleEcho = FALSE;
\r
9643 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9644 /* This works OK: set text and background both to the same color */
\r
9646 cf.crTextColor = COLOR_ECHOOFF;
\r
9647 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9648 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9651 /* No Raw()...? */
\r
9653 void Colorize(ColorClass cc, int continuation)
\r
9655 currentColorClass = cc;
\r
9656 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9657 consoleCF.crTextColor = textAttribs[cc].color;
\r
9658 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9659 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9665 static char buf[MSG_SIZ];
\r
9666 DWORD bufsiz = MSG_SIZ;
\r
9668 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9669 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9671 if (!GetUserName(buf, &bufsiz)) {
\r
9672 /*DisplayError("Error getting user name", GetLastError());*/
\r
9673 strcpy(buf, "User");
\r
9681 static char buf[MSG_SIZ];
\r
9682 DWORD bufsiz = MSG_SIZ;
\r
9684 if (!GetComputerName(buf, &bufsiz)) {
\r
9685 /*DisplayError("Error getting host name", GetLastError());*/
\r
9686 strcpy(buf, "Unknown");
\r
9693 ClockTimerRunning()
\r
9695 return clockTimerEvent != 0;
\r
9701 if (clockTimerEvent == 0) return FALSE;
\r
9702 KillTimer(hwndMain, clockTimerEvent);
\r
9703 clockTimerEvent = 0;
\r
9708 StartClockTimer(long millisec)
\r
9710 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9711 (UINT) millisec, NULL);
\r
9715 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9718 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9720 if(appData.noGUI) return;
\r
9721 hdc = GetDC(hwndMain);
\r
9722 if (!IsIconic(hwndMain)) {
\r
9723 DisplayAClock(hdc, timeRemaining, highlight,
\r
9724 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9726 if (highlight && iconCurrent == iconBlack) {
\r
9727 iconCurrent = iconWhite;
\r
9728 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9729 if (IsIconic(hwndMain)) {
\r
9730 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9733 (void) ReleaseDC(hwndMain, hdc);
\r
9735 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9739 DisplayBlackClock(long timeRemaining, int highlight)
\r
9742 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9744 if(appData.noGUI) return;
\r
9745 hdc = GetDC(hwndMain);
\r
9746 if (!IsIconic(hwndMain)) {
\r
9747 DisplayAClock(hdc, timeRemaining, highlight,
\r
9748 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9750 if (highlight && iconCurrent == iconWhite) {
\r
9751 iconCurrent = iconBlack;
\r
9752 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9753 if (IsIconic(hwndMain)) {
\r
9754 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9757 (void) ReleaseDC(hwndMain, hdc);
\r
9759 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9764 LoadGameTimerRunning()
\r
9766 return loadGameTimerEvent != 0;
\r
9770 StopLoadGameTimer()
\r
9772 if (loadGameTimerEvent == 0) return FALSE;
\r
9773 KillTimer(hwndMain, loadGameTimerEvent);
\r
9774 loadGameTimerEvent = 0;
\r
9779 StartLoadGameTimer(long millisec)
\r
9781 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9782 (UINT) millisec, NULL);
\r
9790 char fileTitle[MSG_SIZ];
\r
9792 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9793 f = OpenFileDialog(hwndMain, "a", defName,
\r
9794 appData.oldSaveStyle ? "gam" : "pgn",
\r
9796 "Save Game to File", NULL, fileTitle, NULL);
\r
9798 SaveGame(f, 0, "");
\r
9805 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9807 if (delayedTimerEvent != 0) {
\r
9808 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9809 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9811 KillTimer(hwndMain, delayedTimerEvent);
\r
9812 delayedTimerEvent = 0;
\r
9813 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9814 delayedTimerCallback();
\r
9816 delayedTimerCallback = cb;
\r
9817 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9818 (UINT) millisec, NULL);
\r
9821 DelayedEventCallback
\r
9824 if (delayedTimerEvent) {
\r
9825 return delayedTimerCallback;
\r
9832 CancelDelayedEvent()
\r
9834 if (delayedTimerEvent) {
\r
9835 KillTimer(hwndMain, delayedTimerEvent);
\r
9836 delayedTimerEvent = 0;
\r
9840 DWORD GetWin32Priority(int nice)
\r
9841 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9843 REALTIME_PRIORITY_CLASS 0x00000100
\r
9844 HIGH_PRIORITY_CLASS 0x00000080
\r
9845 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9846 NORMAL_PRIORITY_CLASS 0x00000020
\r
9847 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9848 IDLE_PRIORITY_CLASS 0x00000040
\r
9850 if (nice < -15) return 0x00000080;
\r
9851 if (nice < 0) return 0x00008000;
\r
9852 if (nice == 0) return 0x00000020;
\r
9853 if (nice < 15) return 0x00004000;
\r
9854 return 0x00000040;
\r
9857 /* Start a child process running the given program.
\r
9858 The process's standard output can be read from "from", and its
\r
9859 standard input can be written to "to".
\r
9860 Exit with fatal error if anything goes wrong.
\r
9861 Returns an opaque pointer that can be used to destroy the process
\r
9865 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9867 #define BUFSIZE 4096
\r
9869 HANDLE hChildStdinRd, hChildStdinWr,
\r
9870 hChildStdoutRd, hChildStdoutWr;
\r
9871 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9872 SECURITY_ATTRIBUTES saAttr;
\r
9874 PROCESS_INFORMATION piProcInfo;
\r
9875 STARTUPINFO siStartInfo;
\r
9877 char buf[MSG_SIZ];
\r
9880 if (appData.debugMode) {
\r
9881 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9886 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9887 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9888 saAttr.bInheritHandle = TRUE;
\r
9889 saAttr.lpSecurityDescriptor = NULL;
\r
9892 * The steps for redirecting child's STDOUT:
\r
9893 * 1. Create anonymous pipe to be STDOUT for child.
\r
9894 * 2. Create a noninheritable duplicate of read handle,
\r
9895 * and close the inheritable read handle.
\r
9898 /* Create a pipe for the child's STDOUT. */
\r
9899 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9900 return GetLastError();
\r
9903 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9904 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9905 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9906 FALSE, /* not inherited */
\r
9907 DUPLICATE_SAME_ACCESS);
\r
9909 return GetLastError();
\r
9911 CloseHandle(hChildStdoutRd);
\r
9914 * The steps for redirecting child's STDIN:
\r
9915 * 1. Create anonymous pipe to be STDIN for child.
\r
9916 * 2. Create a noninheritable duplicate of write handle,
\r
9917 * and close the inheritable write handle.
\r
9920 /* Create a pipe for the child's STDIN. */
\r
9921 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9922 return GetLastError();
\r
9925 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9926 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9927 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9928 FALSE, /* not inherited */
\r
9929 DUPLICATE_SAME_ACCESS);
\r
9931 return GetLastError();
\r
9933 CloseHandle(hChildStdinWr);
\r
9935 /* Arrange to (1) look in dir for the child .exe file, and
\r
9936 * (2) have dir be the child's working directory. Interpret
\r
9937 * dir relative to the directory WinBoard loaded from. */
\r
9938 GetCurrentDirectory(MSG_SIZ, buf);
\r
9939 SetCurrentDirectory(installDir);
\r
9940 SetCurrentDirectory(dir);
\r
9942 /* Now create the child process. */
\r
9944 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9945 siStartInfo.lpReserved = NULL;
\r
9946 siStartInfo.lpDesktop = NULL;
\r
9947 siStartInfo.lpTitle = NULL;
\r
9948 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9949 siStartInfo.cbReserved2 = 0;
\r
9950 siStartInfo.lpReserved2 = NULL;
\r
9951 siStartInfo.hStdInput = hChildStdinRd;
\r
9952 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9953 siStartInfo.hStdError = hChildStdoutWr;
\r
9955 fSuccess = CreateProcess(NULL,
\r
9956 cmdLine, /* command line */
\r
9957 NULL, /* process security attributes */
\r
9958 NULL, /* primary thread security attrs */
\r
9959 TRUE, /* handles are inherited */
\r
9960 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9961 NULL, /* use parent's environment */
\r
9963 &siStartInfo, /* STARTUPINFO pointer */
\r
9964 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9966 err = GetLastError();
\r
9967 SetCurrentDirectory(buf); /* return to prev directory */
\r
9972 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9973 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9974 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9977 /* Close the handles we don't need in the parent */
\r
9978 CloseHandle(piProcInfo.hThread);
\r
9979 CloseHandle(hChildStdinRd);
\r
9980 CloseHandle(hChildStdoutWr);
\r
9982 /* Prepare return value */
\r
9983 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9984 cp->kind = CPReal;
\r
9985 cp->hProcess = piProcInfo.hProcess;
\r
9986 cp->pid = piProcInfo.dwProcessId;
\r
9987 cp->hFrom = hChildStdoutRdDup;
\r
9988 cp->hTo = hChildStdinWrDup;
\r
9990 *pr = (void *) cp;
\r
9992 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9993 2000 where engines sometimes don't see the initial command(s)
\r
9994 from WinBoard and hang. I don't understand how that can happen,
\r
9995 but the Sleep is harmless, so I've put it in. Others have also
\r
9996 reported what may be the same problem, so hopefully this will fix
\r
9997 it for them too. */
\r
10005 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10007 ChildProc *cp; int result;
\r
10009 cp = (ChildProc *) pr;
\r
10010 if (cp == NULL) return;
\r
10012 switch (cp->kind) {
\r
10014 /* TerminateProcess is considered harmful, so... */
\r
10015 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10016 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10017 /* The following doesn't work because the chess program
\r
10018 doesn't "have the same console" as WinBoard. Maybe
\r
10019 we could arrange for this even though neither WinBoard
\r
10020 nor the chess program uses a console for stdio? */
\r
10021 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10023 /* [AS] Special termination modes for misbehaving programs... */
\r
10024 if( signal == 9 ) {
\r
10025 result = TerminateProcess( cp->hProcess, 0 );
\r
10027 if ( appData.debugMode) {
\r
10028 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10031 else if( signal == 10 ) {
\r
10032 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10034 if( dw != WAIT_OBJECT_0 ) {
\r
10035 result = TerminateProcess( cp->hProcess, 0 );
\r
10037 if ( appData.debugMode) {
\r
10038 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10044 CloseHandle(cp->hProcess);
\r
10048 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10052 closesocket(cp->sock);
\r
10057 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10058 closesocket(cp->sock);
\r
10059 closesocket(cp->sock2);
\r
10067 InterruptChildProcess(ProcRef pr)
\r
10071 cp = (ChildProc *) pr;
\r
10072 if (cp == NULL) return;
\r
10073 switch (cp->kind) {
\r
10075 /* The following doesn't work because the chess program
\r
10076 doesn't "have the same console" as WinBoard. Maybe
\r
10077 we could arrange for this even though neither WinBoard
\r
10078 nor the chess program uses a console for stdio */
\r
10079 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10084 /* Can't interrupt */
\r
10088 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10095 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10097 char cmdLine[MSG_SIZ];
\r
10099 if (port[0] == NULLCHAR) {
\r
10100 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10102 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10104 return StartChildProcess(cmdLine, "", pr);
\r
10108 /* Code to open TCP sockets */
\r
10111 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10116 struct sockaddr_in sa, mysa;
\r
10117 struct hostent FAR *hp;
\r
10118 unsigned short uport;
\r
10119 WORD wVersionRequested;
\r
10122 /* Initialize socket DLL */
\r
10123 wVersionRequested = MAKEWORD(1, 1);
\r
10124 err = WSAStartup(wVersionRequested, &wsaData);
\r
10125 if (err != 0) return err;
\r
10127 /* Make socket */
\r
10128 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10129 err = WSAGetLastError();
\r
10134 /* Bind local address using (mostly) don't-care values.
\r
10136 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10137 mysa.sin_family = AF_INET;
\r
10138 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10139 uport = (unsigned short) 0;
\r
10140 mysa.sin_port = htons(uport);
\r
10141 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10142 == SOCKET_ERROR) {
\r
10143 err = WSAGetLastError();
\r
10148 /* Resolve remote host name */
\r
10149 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10150 if (!(hp = gethostbyname(host))) {
\r
10151 unsigned int b0, b1, b2, b3;
\r
10153 err = WSAGetLastError();
\r
10155 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10156 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10157 hp->h_addrtype = AF_INET;
\r
10158 hp->h_length = 4;
\r
10159 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10160 hp->h_addr_list[0] = (char *) malloc(4);
\r
10161 hp->h_addr_list[0][0] = (char) b0;
\r
10162 hp->h_addr_list[0][1] = (char) b1;
\r
10163 hp->h_addr_list[0][2] = (char) b2;
\r
10164 hp->h_addr_list[0][3] = (char) b3;
\r
10170 sa.sin_family = hp->h_addrtype;
\r
10171 uport = (unsigned short) atoi(port);
\r
10172 sa.sin_port = htons(uport);
\r
10173 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10175 /* Make connection */
\r
10176 if (connect(s, (struct sockaddr *) &sa,
\r
10177 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10178 err = WSAGetLastError();
\r
10183 /* Prepare return value */
\r
10184 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10185 cp->kind = CPSock;
\r
10187 *pr = (ProcRef *) cp;
\r
10193 OpenCommPort(char *name, ProcRef *pr)
\r
10198 char fullname[MSG_SIZ];
\r
10200 if (*name != '\\')
\r
10201 sprintf(fullname, "\\\\.\\%s", name);
\r
10203 strcpy(fullname, name);
\r
10205 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10206 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10207 if (h == (HANDLE) -1) {
\r
10208 return GetLastError();
\r
10212 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10214 /* Accumulate characters until a 100ms pause, then parse */
\r
10215 ct.ReadIntervalTimeout = 100;
\r
10216 ct.ReadTotalTimeoutMultiplier = 0;
\r
10217 ct.ReadTotalTimeoutConstant = 0;
\r
10218 ct.WriteTotalTimeoutMultiplier = 0;
\r
10219 ct.WriteTotalTimeoutConstant = 0;
\r
10220 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10222 /* Prepare return value */
\r
10223 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10224 cp->kind = CPComm;
\r
10227 *pr = (ProcRef *) cp;
\r
10233 OpenLoopback(ProcRef *pr)
\r
10235 DisplayFatalError("Not implemented", 0, 1);
\r
10241 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10245 SOCKET s, s2, s3;
\r
10246 struct sockaddr_in sa, mysa;
\r
10247 struct hostent FAR *hp;
\r
10248 unsigned short uport;
\r
10249 WORD wVersionRequested;
\r
10252 char stderrPortStr[MSG_SIZ];
\r
10254 /* Initialize socket DLL */
\r
10255 wVersionRequested = MAKEWORD(1, 1);
\r
10256 err = WSAStartup(wVersionRequested, &wsaData);
\r
10257 if (err != 0) return err;
\r
10259 /* Resolve remote host name */
\r
10260 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10261 if (!(hp = gethostbyname(host))) {
\r
10262 unsigned int b0, b1, b2, b3;
\r
10264 err = WSAGetLastError();
\r
10266 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10267 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10268 hp->h_addrtype = AF_INET;
\r
10269 hp->h_length = 4;
\r
10270 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10271 hp->h_addr_list[0] = (char *) malloc(4);
\r
10272 hp->h_addr_list[0][0] = (char) b0;
\r
10273 hp->h_addr_list[0][1] = (char) b1;
\r
10274 hp->h_addr_list[0][2] = (char) b2;
\r
10275 hp->h_addr_list[0][3] = (char) b3;
\r
10281 sa.sin_family = hp->h_addrtype;
\r
10282 uport = (unsigned short) 514;
\r
10283 sa.sin_port = htons(uport);
\r
10284 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10286 /* Bind local socket to unused "privileged" port address
\r
10288 s = INVALID_SOCKET;
\r
10289 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10290 mysa.sin_family = AF_INET;
\r
10291 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10292 for (fromPort = 1023;; fromPort--) {
\r
10293 if (fromPort < 0) {
\r
10295 return WSAEADDRINUSE;
\r
10297 if (s == INVALID_SOCKET) {
\r
10298 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10299 err = WSAGetLastError();
\r
10304 uport = (unsigned short) fromPort;
\r
10305 mysa.sin_port = htons(uport);
\r
10306 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10307 == SOCKET_ERROR) {
\r
10308 err = WSAGetLastError();
\r
10309 if (err == WSAEADDRINUSE) continue;
\r
10313 if (connect(s, (struct sockaddr *) &sa,
\r
10314 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10315 err = WSAGetLastError();
\r
10316 if (err == WSAEADDRINUSE) {
\r
10327 /* Bind stderr local socket to unused "privileged" port address
\r
10329 s2 = INVALID_SOCKET;
\r
10330 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10331 mysa.sin_family = AF_INET;
\r
10332 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10333 for (fromPort = 1023;; fromPort--) {
\r
10334 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10335 if (fromPort < 0) {
\r
10336 (void) closesocket(s);
\r
10338 return WSAEADDRINUSE;
\r
10340 if (s2 == INVALID_SOCKET) {
\r
10341 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10342 err = WSAGetLastError();
\r
10348 uport = (unsigned short) fromPort;
\r
10349 mysa.sin_port = htons(uport);
\r
10350 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10351 == SOCKET_ERROR) {
\r
10352 err = WSAGetLastError();
\r
10353 if (err == WSAEADDRINUSE) continue;
\r
10354 (void) closesocket(s);
\r
10358 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10359 err = WSAGetLastError();
\r
10360 if (err == WSAEADDRINUSE) {
\r
10362 s2 = INVALID_SOCKET;
\r
10365 (void) closesocket(s);
\r
10366 (void) closesocket(s2);
\r
10372 prevStderrPort = fromPort; // remember port used
\r
10373 sprintf(stderrPortStr, "%d", fromPort);
\r
10375 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10376 err = WSAGetLastError();
\r
10377 (void) closesocket(s);
\r
10378 (void) closesocket(s2);
\r
10383 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10384 err = WSAGetLastError();
\r
10385 (void) closesocket(s);
\r
10386 (void) closesocket(s2);
\r
10390 if (*user == NULLCHAR) user = UserName();
\r
10391 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10392 err = WSAGetLastError();
\r
10393 (void) closesocket(s);
\r
10394 (void) closesocket(s2);
\r
10398 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10399 err = WSAGetLastError();
\r
10400 (void) closesocket(s);
\r
10401 (void) closesocket(s2);
\r
10406 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10407 err = WSAGetLastError();
\r
10408 (void) closesocket(s);
\r
10409 (void) closesocket(s2);
\r
10413 (void) closesocket(s2); /* Stop listening */
\r
10415 /* Prepare return value */
\r
10416 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10417 cp->kind = CPRcmd;
\r
10420 *pr = (ProcRef *) cp;
\r
10427 AddInputSource(ProcRef pr, int lineByLine,
\r
10428 InputCallback func, VOIDSTAR closure)
\r
10430 InputSource *is, *is2 = NULL;
\r
10431 ChildProc *cp = (ChildProc *) pr;
\r
10433 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10434 is->lineByLine = lineByLine;
\r
10436 is->closure = closure;
\r
10437 is->second = NULL;
\r
10438 is->next = is->buf;
\r
10439 if (pr == NoProc) {
\r
10440 is->kind = CPReal;
\r
10441 consoleInputSource = is;
\r
10443 is->kind = cp->kind;
\r
10445 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10446 we create all threads suspended so that the is->hThread variable can be
\r
10447 safely assigned, then let the threads start with ResumeThread.
\r
10449 switch (cp->kind) {
\r
10451 is->hFile = cp->hFrom;
\r
10452 cp->hFrom = NULL; /* now owned by InputThread */
\r
10454 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10455 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10459 is->hFile = cp->hFrom;
\r
10460 cp->hFrom = NULL; /* now owned by InputThread */
\r
10462 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10463 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10467 is->sock = cp->sock;
\r
10469 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10470 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10474 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10476 is->sock = cp->sock;
\r
10477 is->second = is2;
\r
10478 is2->sock = cp->sock2;
\r
10479 is2->second = is2;
\r
10481 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10482 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10484 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10485 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10489 if( is->hThread != NULL ) {
\r
10490 ResumeThread( is->hThread );
\r
10493 if( is2 != NULL && is2->hThread != NULL ) {
\r
10494 ResumeThread( is2->hThread );
\r
10498 return (InputSourceRef) is;
\r
10502 RemoveInputSource(InputSourceRef isr)
\r
10506 is = (InputSource *) isr;
\r
10507 is->hThread = NULL; /* tell thread to stop */
\r
10508 CloseHandle(is->hThread);
\r
10509 if (is->second != NULL) {
\r
10510 is->second->hThread = NULL;
\r
10511 CloseHandle(is->second->hThread);
\r
10517 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10520 int outCount = SOCKET_ERROR;
\r
10521 ChildProc *cp = (ChildProc *) pr;
\r
10522 static OVERLAPPED ovl;
\r
10524 if (pr == NoProc) {
\r
10525 ConsoleOutput(message, count, FALSE);
\r
10529 if (ovl.hEvent == NULL) {
\r
10530 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10532 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10534 switch (cp->kind) {
\r
10537 outCount = send(cp->sock, message, count, 0);
\r
10538 if (outCount == SOCKET_ERROR) {
\r
10539 *outError = WSAGetLastError();
\r
10541 *outError = NO_ERROR;
\r
10546 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10547 &dOutCount, NULL)) {
\r
10548 *outError = NO_ERROR;
\r
10549 outCount = (int) dOutCount;
\r
10551 *outError = GetLastError();
\r
10556 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10557 &dOutCount, &ovl);
\r
10558 if (*outError == NO_ERROR) {
\r
10559 outCount = (int) dOutCount;
\r
10567 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10570 /* Ignore delay, not implemented for WinBoard */
\r
10571 return OutputToProcess(pr, message, count, outError);
\r
10576 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10577 char *buf, int count, int error)
\r
10579 DisplayFatalError("Not implemented", 0, 1);
\r
10582 /* see wgamelist.c for Game List functions */
\r
10583 /* see wedittags.c for Edit Tags functions */
\r
10590 char buf[MSG_SIZ];
\r
10593 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10594 f = fopen(buf, "r");
\r
10596 ProcessICSInitScript(f);
\r
10604 StartAnalysisClock()
\r
10606 if (analysisTimerEvent) return;
\r
10607 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10608 (UINT) 2000, NULL);
\r
10612 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10614 static HANDLE hwndText;
\r
10616 static int sizeX, sizeY;
\r
10617 int newSizeX, newSizeY, flags;
\r
10620 switch (message) {
\r
10621 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10622 /* Initialize the dialog items */
\r
10623 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10624 SetWindowText(hDlg, analysisTitle);
\r
10625 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10626 /* Size and position the dialog */
\r
10627 if (!analysisDialog) {
\r
10628 analysisDialog = hDlg;
\r
10629 flags = SWP_NOZORDER;
\r
10630 GetClientRect(hDlg, &rect);
\r
10631 sizeX = rect.right;
\r
10632 sizeY = rect.bottom;
\r
10633 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10634 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10635 WINDOWPLACEMENT wp;
\r
10636 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10637 wp.length = sizeof(WINDOWPLACEMENT);
\r
10639 wp.showCmd = SW_SHOW;
\r
10640 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10641 wp.rcNormalPosition.left = analysisX;
\r
10642 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10643 wp.rcNormalPosition.top = analysisY;
\r
10644 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10645 SetWindowPlacement(hDlg, &wp);
\r
10647 GetClientRect(hDlg, &rect);
\r
10648 newSizeX = rect.right;
\r
10649 newSizeY = rect.bottom;
\r
10650 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10651 newSizeX, newSizeY);
\r
10652 sizeX = newSizeX;
\r
10653 sizeY = newSizeY;
\r
10658 case WM_COMMAND: /* message: received a command */
\r
10659 switch (LOWORD(wParam)) {
\r
10661 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10662 ExitAnalyzeMode();
\r
10674 newSizeX = LOWORD(lParam);
\r
10675 newSizeY = HIWORD(lParam);
\r
10676 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10677 sizeX = newSizeX;
\r
10678 sizeY = newSizeY;
\r
10681 case WM_GETMINMAXINFO:
\r
10682 /* Prevent resizing window too small */
\r
10683 mmi = (MINMAXINFO *) lParam;
\r
10684 mmi->ptMinTrackSize.x = 100;
\r
10685 mmi->ptMinTrackSize.y = 100;
\r
10692 AnalysisPopUp(char* title, char* str)
\r
10698 EngineOutputPopUp();
\r
10701 if (str == NULL) str = "";
\r
10702 p = (char *) malloc(2 * strlen(str) + 2);
\r
10705 if (*str == '\n') *q++ = '\r';
\r
10709 if (analysisText != NULL) free(analysisText);
\r
10710 analysisText = p;
\r
10712 if (analysisDialog) {
\r
10713 SetWindowText(analysisDialog, title);
\r
10714 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10715 ShowWindow(analysisDialog, SW_SHOW);
\r
10717 analysisTitle = title;
\r
10718 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10719 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10720 hwndMain, (DLGPROC)lpProc);
\r
10721 FreeProcInstance(lpProc);
\r
10723 analysisDialogUp = TRUE;
\r
10727 AnalysisPopDown()
\r
10729 if (analysisDialog) {
\r
10730 ShowWindow(analysisDialog, SW_HIDE);
\r
10732 analysisDialogUp = FALSE;
\r
10737 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10739 highlightInfo.sq[0].x = fromX;
\r
10740 highlightInfo.sq[0].y = fromY;
\r
10741 highlightInfo.sq[1].x = toX;
\r
10742 highlightInfo.sq[1].y = toY;
\r
10746 ClearHighlights()
\r
10748 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10749 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10753 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10755 premoveHighlightInfo.sq[0].x = fromX;
\r
10756 premoveHighlightInfo.sq[0].y = fromY;
\r
10757 premoveHighlightInfo.sq[1].x = toX;
\r
10758 premoveHighlightInfo.sq[1].y = toY;
\r
10762 ClearPremoveHighlights()
\r
10764 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10765 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10769 ShutDownFrontEnd()
\r
10771 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10772 DeleteClipboardTempFiles();
\r
10778 if (IsIconic(hwndMain))
\r
10779 ShowWindow(hwndMain, SW_RESTORE);
\r
10781 SetActiveWindow(hwndMain);
\r
10785 * Prototypes for animation support routines
\r
10787 static void ScreenSquare(int column, int row, POINT * pt);
\r
10788 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10789 POINT frames[], int * nFrames);
\r
10793 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10794 { // [HGM] atomic: animate blast wave
\r
10796 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10797 explodeInfo.fromX = fromX;
\r
10798 explodeInfo.fromY = fromY;
\r
10799 explodeInfo.toX = toX;
\r
10800 explodeInfo.toY = toY;
\r
10801 for(i=1; i<nFrames; i++) {
\r
10802 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10803 DrawPosition(FALSE, NULL);
\r
10804 Sleep(appData.animSpeed);
\r
10806 explodeInfo.radius = 0;
\r
10807 DrawPosition(TRUE, NULL);
\r
10810 #define kFactor 4
\r
10813 AnimateMove(board, fromX, fromY, toX, toY)
\r
10820 ChessSquare piece;
\r
10821 POINT start, finish, mid;
\r
10822 POINT frames[kFactor * 2 + 1];
\r
10825 if (!appData.animate) return;
\r
10826 if (doingSizing) return;
\r
10827 if (fromY < 0 || fromX < 0) return;
\r
10828 piece = board[fromY][fromX];
\r
10829 if (piece >= EmptySquare) return;
\r
10831 ScreenSquare(fromX, fromY, &start);
\r
10832 ScreenSquare(toX, toY, &finish);
\r
10834 /* All pieces except knights move in straight line */
\r
10835 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10836 mid.x = start.x + (finish.x - start.x) / 2;
\r
10837 mid.y = start.y + (finish.y - start.y) / 2;
\r
10839 /* Knight: make diagonal movement then straight */
\r
10840 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10841 mid.x = start.x + (finish.x - start.x) / 2;
\r
10842 mid.y = finish.y;
\r
10844 mid.x = finish.x;
\r
10845 mid.y = start.y + (finish.y - start.y) / 2;
\r
10849 /* Don't use as many frames for very short moves */
\r
10850 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10851 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10853 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10855 animInfo.from.x = fromX;
\r
10856 animInfo.from.y = fromY;
\r
10857 animInfo.to.x = toX;
\r
10858 animInfo.to.y = toY;
\r
10859 animInfo.lastpos = start;
\r
10860 animInfo.piece = piece;
\r
10861 for (n = 0; n < nFrames; n++) {
\r
10862 animInfo.pos = frames[n];
\r
10863 DrawPosition(FALSE, NULL);
\r
10864 animInfo.lastpos = animInfo.pos;
\r
10865 Sleep(appData.animSpeed);
\r
10867 animInfo.pos = finish;
\r
10868 DrawPosition(FALSE, NULL);
\r
10869 animInfo.piece = EmptySquare;
\r
10870 if(gameInfo.variant == VariantAtomic &&
\r
10871 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10872 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10875 /* Convert board position to corner of screen rect and color */
\r
10878 ScreenSquare(column, row, pt)
\r
10879 int column; int row; POINT * pt;
\r
10882 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10883 pt->y = lineGap + row * (squareSize + lineGap);
\r
10885 pt->x = lineGap + column * (squareSize + lineGap);
\r
10886 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10890 /* Generate a series of frame coords from start->mid->finish.
\r
10891 The movement rate doubles until the half way point is
\r
10892 reached, then halves back down to the final destination,
\r
10893 which gives a nice slow in/out effect. The algorithmn
\r
10894 may seem to generate too many intermediates for short
\r
10895 moves, but remember that the purpose is to attract the
\r
10896 viewers attention to the piece about to be moved and
\r
10897 then to where it ends up. Too few frames would be less
\r
10901 Tween(start, mid, finish, factor, frames, nFrames)
\r
10902 POINT * start; POINT * mid;
\r
10903 POINT * finish; int factor;
\r
10904 POINT frames[]; int * nFrames;
\r
10906 int n, fraction = 1, count = 0;
\r
10908 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10909 for (n = 0; n < factor; n++)
\r
10911 for (n = 0; n < factor; n++) {
\r
10912 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10913 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10915 fraction = fraction / 2;
\r
10919 frames[count] = *mid;
\r
10922 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10924 for (n = 0; n < factor; n++) {
\r
10925 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10926 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10928 fraction = fraction * 2;
\r
10930 *nFrames = count;
\r
10934 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10936 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10938 EvalGraphSet( first, last, current, pvInfoList );
\r
10941 void SetProgramStats( FrontEndProgramStats * stats )
\r
10943 EngineOutputUpdate( stats );
\r