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
1395 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },
\r
1397 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1398 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1399 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1400 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1401 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1402 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1403 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1404 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1405 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1406 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1407 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1408 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1409 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1410 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1411 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1412 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1413 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1414 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1415 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1416 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1417 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1418 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1419 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1420 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1421 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1422 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1423 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1424 /* [AS] Layout stuff */
\r
1425 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1426 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1427 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1428 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1429 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1431 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1432 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1433 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1434 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1435 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1437 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1438 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1439 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1440 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1441 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1443 { NULL, ArgNone, NULL, FALSE }
\r
1447 /* Kludge for indirection files on command line */
\r
1448 char* lastIndirectionFilename;
\r
1449 ArgDescriptor argDescriptorIndirection =
\r
1450 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1454 ExitArgError(char *msg, char *badArg)
\r
1456 char buf[MSG_SIZ];
\r
1458 sprintf(buf, "%s %s", msg, badArg);
\r
1459 DisplayFatalError(buf, 0, 2);
\r
1463 /* Command line font name parser. NULL name means do nothing.
\r
1464 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1465 For backward compatibility, syntax without the colon is also
\r
1466 accepted, but font names with digits in them won't work in that case.
\r
1469 ParseFontName(char *name, MyFontParams *mfp)
\r
1472 if (name == NULL) return;
\r
1474 q = strchr(p, ':');
\r
1476 if (q - p >= sizeof(mfp->faceName))
\r
1477 ExitArgError("Font name too long:", name);
\r
1478 memcpy(mfp->faceName, p, q - p);
\r
1479 mfp->faceName[q - p] = NULLCHAR;
\r
1482 q = mfp->faceName;
\r
1483 while (*p && !isdigit(*p)) {
\r
1485 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1486 ExitArgError("Font name too long:", name);
\r
1488 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1491 if (!*p) ExitArgError("Font point size missing:", name);
\r
1492 mfp->pointSize = (float) atof(p);
\r
1493 mfp->bold = (strchr(p, 'b') != NULL);
\r
1494 mfp->italic = (strchr(p, 'i') != NULL);
\r
1495 mfp->underline = (strchr(p, 'u') != NULL);
\r
1496 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1499 /* Color name parser.
\r
1500 X version accepts X color names, but this one
\r
1501 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1503 ParseColorName(char *name)
\r
1505 int red, green, blue, count;
\r
1506 char buf[MSG_SIZ];
\r
1508 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1510 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1511 &red, &green, &blue);
\r
1514 sprintf(buf, "Can't parse color name %s", name);
\r
1515 DisplayError(buf, 0);
\r
1516 return RGB(0, 0, 0);
\r
1518 return PALETTERGB(red, green, blue);
\r
1522 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1524 char *e = argValue;
\r
1528 if (*e == 'b') eff |= CFE_BOLD;
\r
1529 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1530 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1531 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1532 else if (*e == '#' || isdigit(*e)) break;
\r
1536 *color = ParseColorName(e);
\r
1541 ParseBoardSize(char *name)
\r
1543 BoardSize bs = SizeTiny;
\r
1544 while (sizeInfo[bs].name != NULL) {
\r
1545 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1548 ExitArgError("Unrecognized board size value", name);
\r
1549 return bs; /* not reached */
\r
1554 StringGet(void *getClosure)
\r
1556 char **p = (char **) getClosure;
\r
1561 FileGet(void *getClosure)
\r
1564 FILE* f = (FILE*) getClosure;
\r
1567 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1574 /* Parse settings file named "name". If file found, return the
\r
1575 full name in fullname and return TRUE; else return FALSE */
\r
1577 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1581 int ok; char buf[MSG_SIZ];
\r
1583 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1584 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1585 sprintf(buf, "%s.ini", name);
\r
1586 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1589 f = fopen(fullname, "r");
\r
1591 ParseArgs(FileGet, f);
\r
1600 ParseArgs(GetFunc get, void *cl)
\r
1602 char argName[ARG_MAX];
\r
1603 char argValue[ARG_MAX];
\r
1604 ArgDescriptor *ad;
\r
1613 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1614 if (ch == NULLCHAR) break;
\r
1616 /* Comment to end of line */
\r
1618 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1620 } else if (ch == '/' || ch == '-') {
\r
1623 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1624 ch != '\n' && ch != '\t') {
\r
1630 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1631 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1633 if (ad->argName == NULL)
\r
1634 ExitArgError("Unrecognized argument", argName);
\r
1636 } else if (ch == '@') {
\r
1637 /* Indirection file */
\r
1638 ad = &argDescriptorIndirection;
\r
1641 /* Positional argument */
\r
1642 ad = &argDescriptors[posarg++];
\r
1643 strcpy(argName, ad->argName);
\r
1646 if (ad->argType == ArgTrue) {
\r
1647 *(Boolean *) ad->argLoc = TRUE;
\r
1650 if (ad->argType == ArgFalse) {
\r
1651 *(Boolean *) ad->argLoc = FALSE;
\r
1655 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1656 if (ch == NULLCHAR || ch == '\n') {
\r
1657 ExitArgError("No value provided for argument", argName);
\r
1661 // Quoting with { }. No characters have to (or can) be escaped.
\r
1662 // Thus the string cannot contain a '}' character.
\r
1682 } else if (ch == '\'' || ch == '"') {
\r
1683 // Quoting with ' ' or " ", with \ as escape character.
\r
1684 // Inconvenient for long strings that may contain Windows filenames.
\r
1701 if (ch == start) {
\r
1710 if (ad->argType == ArgFilename
\r
1711 || ad->argType == ArgSettingsFilename) {
\r
1717 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1741 for (i = 0; i < 3; i++) {
\r
1742 if (ch >= '0' && ch <= '7') {
\r
1743 octval = octval*8 + (ch - '0');
\r
1750 *q++ = (char) octval;
\r
1761 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1768 switch (ad->argType) {
\r
1770 *(int *) ad->argLoc = atoi(argValue);
\r
1774 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1778 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1782 *(int *) ad->argLoc = atoi(argValue);
\r
1783 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1787 *(float *) ad->argLoc = (float) atof(argValue);
\r
1792 *(char **) ad->argLoc = strdup(argValue);
\r
1795 case ArgSettingsFilename:
\r
1797 char fullname[MSG_SIZ];
\r
1798 if (ParseSettingsFile(argValue, fullname)) {
\r
1799 if (ad->argLoc != NULL) {
\r
1800 *(char **) ad->argLoc = strdup(fullname);
\r
1803 if (ad->argLoc != NULL) {
\r
1805 ExitArgError("Failed to open indirection file", argValue);
\r
1812 switch (argValue[0]) {
\r
1815 *(Boolean *) ad->argLoc = TRUE;
\r
1819 *(Boolean *) ad->argLoc = FALSE;
\r
1822 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1828 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1831 case ArgAttribs: {
\r
1832 ColorClass cc = (ColorClass)ad->argLoc;
\r
1833 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1837 case ArgBoardSize:
\r
1838 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1842 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1845 case ArgCommSettings:
\r
1846 ParseCommSettings(argValue, &dcb);
\r
1850 ExitArgError("Unrecognized argument", argValue);
\r
1859 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1861 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1862 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1865 lf->lfEscapement = 0;
\r
1866 lf->lfOrientation = 0;
\r
1867 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1868 lf->lfItalic = mfp->italic;
\r
1869 lf->lfUnderline = mfp->underline;
\r
1870 lf->lfStrikeOut = mfp->strikeout;
\r
1871 lf->lfCharSet = DEFAULT_CHARSET;
\r
1872 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1873 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1874 lf->lfQuality = DEFAULT_QUALITY;
\r
1875 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1876 strcpy(lf->lfFaceName, mfp->faceName);
\r
1880 CreateFontInMF(MyFont *mf)
\r
1882 LFfromMFP(&mf->lf, &mf->mfp);
\r
1883 if (mf->hf) DeleteObject(mf->hf);
\r
1884 mf->hf = CreateFontIndirect(&mf->lf);
\r
1888 SetDefaultTextAttribs()
\r
1891 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1892 ParseAttribs(&textAttribs[cc].color,
\r
1893 &textAttribs[cc].effects,
\r
1894 defaultTextAttribs[cc]);
\r
1899 SetDefaultSounds()
\r
1903 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1904 textAttribs[cc].sound.name = strdup("");
\r
1905 textAttribs[cc].sound.data = NULL;
\r
1907 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1908 sounds[sc].name = strdup("");
\r
1909 sounds[sc].data = NULL;
\r
1911 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1919 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1920 MyLoadSound(&textAttribs[cc].sound);
\r
1922 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1923 MyLoadSound(&sounds[sc]);
\r
1928 InitAppData(LPSTR lpCmdLine)
\r
1931 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1934 programName = szAppName;
\r
1936 /* Initialize to defaults */
\r
1937 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1938 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1939 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1940 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1941 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1942 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1943 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1944 SetDefaultTextAttribs();
\r
1945 SetDefaultSounds();
\r
1946 appData.movesPerSession = MOVES_PER_SESSION;
\r
1947 appData.initString = INIT_STRING;
\r
1948 appData.secondInitString = INIT_STRING;
\r
1949 appData.firstComputerString = COMPUTER_STRING;
\r
1950 appData.secondComputerString = COMPUTER_STRING;
\r
1951 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1952 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1953 appData.firstPlaysBlack = FALSE;
\r
1954 appData.noChessProgram = FALSE;
\r
1955 chessProgram = FALSE;
\r
1956 appData.firstHost = FIRST_HOST;
\r
1957 appData.secondHost = SECOND_HOST;
\r
1958 appData.firstDirectory = FIRST_DIRECTORY;
\r
1959 appData.secondDirectory = SECOND_DIRECTORY;
\r
1960 appData.bitmapDirectory = "";
\r
1961 appData.remoteShell = REMOTE_SHELL;
\r
1962 appData.remoteUser = "";
\r
1963 appData.timeDelay = TIME_DELAY;
\r
1964 appData.timeControl = TIME_CONTROL;
\r
1965 appData.timeIncrement = TIME_INCREMENT;
\r
1966 appData.icsActive = FALSE;
\r
1967 appData.icsHost = "";
\r
1968 appData.icsPort = ICS_PORT;
\r
1969 appData.icsCommPort = ICS_COMM_PORT;
\r
1970 appData.icsLogon = ICS_LOGON;
\r
1971 appData.icsHelper = "";
\r
1972 appData.useTelnet = FALSE;
\r
1973 appData.telnetProgram = TELNET_PROGRAM;
\r
1974 appData.gateway = "";
\r
1975 appData.loadGameFile = "";
\r
1976 appData.loadGameIndex = 0;
\r
1977 appData.saveGameFile = "";
\r
1978 appData.autoSaveGames = FALSE;
\r
1979 appData.loadPositionFile = "";
\r
1980 appData.loadPositionIndex = 1;
\r
1981 appData.savePositionFile = "";
\r
1982 appData.matchMode = FALSE;
\r
1983 appData.matchGames = 0;
\r
1984 appData.monoMode = FALSE;
\r
1985 appData.debugMode = FALSE;
\r
1986 appData.clockMode = TRUE;
\r
1987 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1988 appData.Iconic = FALSE; /*unused*/
\r
1989 appData.searchTime = "";
\r
1990 appData.searchDepth = 0;
\r
1991 appData.showCoords = FALSE;
\r
1992 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1993 appData.autoCallFlag = FALSE;
\r
1994 appData.flipView = FALSE;
\r
1995 appData.autoFlipView = TRUE;
\r
1996 appData.cmailGameName = "";
\r
1997 appData.alwaysPromoteToQueen = FALSE;
\r
1998 appData.oldSaveStyle = FALSE;
\r
1999 appData.quietPlay = FALSE;
\r
2000 appData.showThinking = FALSE;
\r
2001 appData.ponderNextMove = TRUE;
\r
2002 appData.periodicUpdates = TRUE;
\r
2003 appData.popupExitMessage = TRUE;
\r
2004 appData.popupMoveErrors = FALSE;
\r
2005 appData.autoObserve = FALSE;
\r
2006 appData.autoComment = FALSE;
\r
2007 appData.animate = TRUE;
\r
2008 appData.animSpeed = 10;
\r
2009 appData.animateDragging = TRUE;
\r
2010 appData.highlightLastMove = TRUE;
\r
2011 appData.getMoveList = TRUE;
\r
2012 appData.testLegality = TRUE;
\r
2013 appData.premove = TRUE;
\r
2014 appData.premoveWhite = FALSE;
\r
2015 appData.premoveWhiteText = "";
\r
2016 appData.premoveBlack = FALSE;
\r
2017 appData.premoveBlackText = "";
\r
2018 appData.icsAlarm = TRUE;
\r
2019 appData.icsAlarmTime = 5000;
\r
2020 appData.autoRaiseBoard = TRUE;
\r
2021 appData.localLineEditing = TRUE;
\r
2022 appData.colorize = TRUE;
\r
2023 appData.reuseFirst = TRUE;
\r
2024 appData.reuseSecond = TRUE;
\r
2025 appData.blindfold = FALSE;
\r
2026 appData.icsEngineAnalyze = FALSE;
\r
2027 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2028 dcb.DCBlength = sizeof(DCB);
\r
2029 dcb.BaudRate = 9600;
\r
2030 dcb.fBinary = TRUE;
\r
2031 dcb.fParity = FALSE;
\r
2032 dcb.fOutxCtsFlow = FALSE;
\r
2033 dcb.fOutxDsrFlow = FALSE;
\r
2034 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2035 dcb.fDsrSensitivity = FALSE;
\r
2036 dcb.fTXContinueOnXoff = TRUE;
\r
2037 dcb.fOutX = FALSE;
\r
2039 dcb.fNull = FALSE;
\r
2040 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2041 dcb.fAbortOnError = FALSE;
\r
2043 dcb.Parity = SPACEPARITY;
\r
2044 dcb.StopBits = ONESTOPBIT;
\r
2045 settingsFileName = SETTINGS_FILE;
\r
2046 saveSettingsOnExit = TRUE;
\r
2047 boardX = CW_USEDEFAULT;
\r
2048 boardY = CW_USEDEFAULT;
\r
2049 analysisX = CW_USEDEFAULT;
\r
2050 analysisY = CW_USEDEFAULT;
\r
2051 analysisW = CW_USEDEFAULT;
\r
2052 analysisH = CW_USEDEFAULT;
\r
2053 commentX = CW_USEDEFAULT;
\r
2054 commentY = CW_USEDEFAULT;
\r
2055 commentW = CW_USEDEFAULT;
\r
2056 commentH = CW_USEDEFAULT;
\r
2057 editTagsX = CW_USEDEFAULT;
\r
2058 editTagsY = CW_USEDEFAULT;
\r
2059 editTagsW = CW_USEDEFAULT;
\r
2060 editTagsH = CW_USEDEFAULT;
\r
2061 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2062 icsNames = ICS_NAMES;
\r
2063 firstChessProgramNames = FCP_NAMES;
\r
2064 secondChessProgramNames = SCP_NAMES;
\r
2065 appData.initialMode = "";
\r
2066 appData.variant = "normal";
\r
2067 appData.firstProtocolVersion = PROTOVER;
\r
2068 appData.secondProtocolVersion = PROTOVER;
\r
2069 appData.showButtonBar = TRUE;
\r
2071 /* [AS] New properties (see comments in header file) */
\r
2072 appData.firstScoreIsAbsolute = FALSE;
\r
2073 appData.secondScoreIsAbsolute = FALSE;
\r
2074 appData.saveExtendedInfoInPGN = FALSE;
\r
2075 appData.hideThinkingFromHuman = FALSE;
\r
2076 appData.liteBackTextureFile = "";
\r
2077 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2078 appData.darkBackTextureFile = "";
\r
2079 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2080 appData.renderPiecesWithFont = "";
\r
2081 appData.fontToPieceTable = "";
\r
2082 appData.fontBackColorWhite = 0;
\r
2083 appData.fontForeColorWhite = 0;
\r
2084 appData.fontBackColorBlack = 0;
\r
2085 appData.fontForeColorBlack = 0;
\r
2086 appData.fontPieceSize = 80;
\r
2087 appData.overrideLineGap = 1;
\r
2088 appData.adjudicateLossThreshold = 0;
\r
2089 appData.delayBeforeQuit = 0;
\r
2090 appData.delayAfterQuit = 0;
\r
2091 appData.nameOfDebugFile = "winboard.debug";
\r
2092 appData.pgnEventHeader = "Computer Chess Game";
\r
2093 appData.defaultFrcPosition = -1;
\r
2094 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2095 appData.saveOutOfBookInfo = TRUE;
\r
2096 appData.showEvalInMoveHistory = TRUE;
\r
2097 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2098 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2099 appData.highlightMoveWithArrow = FALSE;
\r
2100 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2101 appData.useStickyWindows = TRUE;
\r
2102 appData.adjudicateDrawMoves = 0;
\r
2103 appData.autoDisplayComment = TRUE;
\r
2104 appData.autoDisplayTags = TRUE;
\r
2105 appData.firstIsUCI = FALSE;
\r
2106 appData.secondIsUCI = FALSE;
\r
2107 appData.firstHasOwnBookUCI = TRUE;
\r
2108 appData.secondHasOwnBookUCI = TRUE;
\r
2109 appData.polyglotDir = "";
\r
2110 appData.usePolyglotBook = FALSE;
\r
2111 appData.polyglotBook = "";
\r
2112 appData.defaultHashSize = 64;
\r
2113 appData.defaultCacheSizeEGTB = 4;
\r
2114 appData.defaultPathEGTB = "c:\\egtb";
\r
2115 appData.firstOptions = "";
\r
2116 appData.secondOptions = "";
\r
2118 InitWindowPlacement( &wpGameList );
\r
2119 InitWindowPlacement( &wpMoveHistory );
\r
2120 InitWindowPlacement( &wpEvalGraph );
\r
2121 InitWindowPlacement( &wpEngineOutput );
\r
2122 InitWindowPlacement( &wpConsole );
\r
2124 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2125 appData.NrFiles = -1;
\r
2126 appData.NrRanks = -1;
\r
2127 appData.holdingsSize = -1;
\r
2128 appData.testClaims = FALSE;
\r
2129 appData.checkMates = FALSE;
\r
2130 appData.materialDraws= FALSE;
\r
2131 appData.trivialDraws = FALSE;
\r
2132 appData.ruleMoves = 51;
\r
2133 appData.drawRepeats = 6;
\r
2134 appData.matchPause = 10000;
\r
2135 appData.alphaRank = FALSE;
\r
2136 appData.allWhite = FALSE;
\r
2137 appData.upsideDown = FALSE;
\r
2138 appData.serverPause = 15;
\r
2139 appData.serverMovesName = NULL;
\r
2140 appData.suppressLoadMoves = FALSE;
\r
2141 appData.firstTimeOdds = 1;
\r
2142 appData.secondTimeOdds = 1;
\r
2143 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2144 appData.secondAccumulateTC = 1;
\r
2145 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2146 appData.secondNPS = -1;
\r
2147 appData.engineComments = 1;
\r
2148 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2149 appData.egtFormats = "";
\r
2152 appData.zippyTalk = ZIPPY_TALK;
\r
2153 appData.zippyPlay = ZIPPY_PLAY;
\r
2154 appData.zippyLines = ZIPPY_LINES;
\r
2155 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2156 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2157 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2158 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2159 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2160 appData.zippyUseI = ZIPPY_USE_I;
\r
2161 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2162 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2163 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2164 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2165 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2166 appData.zippyAbort = ZIPPY_ABORT;
\r
2167 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2168 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2169 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2172 /* Point font array elements to structures and
\r
2173 parse default font names */
\r
2174 for (i=0; i<NUM_FONTS; i++) {
\r
2175 for (j=0; j<NUM_SIZES; j++) {
\r
2176 font[j][i] = &fontRec[j][i];
\r
2177 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2181 /* Parse default settings file if any */
\r
2182 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2183 settingsFileName = strdup(buf);
\r
2186 /* Parse command line */
\r
2187 ParseArgs(StringGet, &lpCmdLine);
\r
2189 /* [HGM] make sure board size is acceptable */
\r
2190 if(appData.NrFiles > BOARD_SIZE ||
\r
2191 appData.NrRanks > BOARD_SIZE )
\r
2192 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2194 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2195 * with options from the command line, we now make an even higher priority
\r
2196 * overrule by WB options attached to the engine command line. This so that
\r
2197 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2200 if(appData.firstChessProgram != NULL) {
\r
2201 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2202 static char *f = "first";
\r
2203 char buf[MSG_SIZ], *q = buf;
\r
2204 if(p != NULL) { // engine command line contains WinBoard options
\r
2205 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2206 ParseArgs(StringGet, &q);
\r
2207 p[-1] = 0; // cut them offengine command line
\r
2210 // now do same for second chess program
\r
2211 if(appData.secondChessProgram != NULL) {
\r
2212 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2213 static char *s = "second";
\r
2214 char buf[MSG_SIZ], *q = buf;
\r
2215 if(p != NULL) { // engine command line contains WinBoard options
\r
2216 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2217 ParseArgs(StringGet, &q);
\r
2218 p[-1] = 0; // cut them offengine command line
\r
2223 /* Propagate options that affect others */
\r
2224 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2225 if (appData.icsActive || appData.noChessProgram) {
\r
2226 chessProgram = FALSE; /* not local chess program mode */
\r
2229 /* Open startup dialog if needed */
\r
2230 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2231 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2232 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2233 *appData.secondChessProgram == NULLCHAR))) {
\r
2236 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2237 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2238 FreeProcInstance(lpProc);
\r
2241 /* Make sure save files land in the right (?) directory */
\r
2242 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2243 appData.saveGameFile = strdup(buf);
\r
2245 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2246 appData.savePositionFile = strdup(buf);
\r
2249 /* Finish initialization for fonts and sounds */
\r
2250 for (i=0; i<NUM_FONTS; i++) {
\r
2251 for (j=0; j<NUM_SIZES; j++) {
\r
2252 CreateFontInMF(font[j][i]);
\r
2255 /* xboard, and older WinBoards, controlled the move sound with the
\r
2256 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2257 always turn the option on (so that the backend will call us),
\r
2258 then let the user turn the sound off by setting it to silence if
\r
2259 desired. To accommodate old winboard.ini files saved by old
\r
2260 versions of WinBoard, we also turn off the sound if the option
\r
2261 was initially set to false. */
\r
2262 if (!appData.ringBellAfterMoves) {
\r
2263 sounds[(int)SoundMove].name = strdup("");
\r
2264 appData.ringBellAfterMoves = TRUE;
\r
2266 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2267 SetCurrentDirectory(installDir);
\r
2269 SetCurrentDirectory(currDir);
\r
2271 p = icsTextMenuString;
\r
2272 if (p[0] == '@') {
\r
2273 FILE* f = fopen(p + 1, "r");
\r
2275 DisplayFatalError(p + 1, errno, 2);
\r
2278 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2280 buf[i] = NULLCHAR;
\r
2283 ParseIcsTextMenu(strdup(p));
\r
2290 HMENU hmenu = GetMenu(hwndMain);
\r
2292 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2293 MF_BYCOMMAND|((appData.icsActive &&
\r
2294 *appData.icsCommPort != NULLCHAR) ?
\r
2295 MF_ENABLED : MF_GRAYED));
\r
2296 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2297 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2298 MF_CHECKED : MF_UNCHECKED));
\r
2303 SaveSettings(char* name)
\r
2306 ArgDescriptor *ad;
\r
2307 WINDOWPLACEMENT wp;
\r
2308 char dir[MSG_SIZ];
\r
2310 if (!hwndMain) return;
\r
2312 GetCurrentDirectory(MSG_SIZ, dir);
\r
2313 SetCurrentDirectory(installDir);
\r
2314 f = fopen(name, "w");
\r
2315 SetCurrentDirectory(dir);
\r
2317 DisplayError(name, errno);
\r
2320 fprintf(f, ";\n");
\r
2321 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2322 fprintf(f, ";\n");
\r
2323 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2324 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2325 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2326 fprintf(f, ";\n");
\r
2328 wp.length = sizeof(WINDOWPLACEMENT);
\r
2329 GetWindowPlacement(hwndMain, &wp);
\r
2330 boardX = wp.rcNormalPosition.left;
\r
2331 boardY = wp.rcNormalPosition.top;
\r
2333 if (hwndConsole) {
\r
2334 GetWindowPlacement(hwndConsole, &wp);
\r
2335 wpConsole.x = wp.rcNormalPosition.left;
\r
2336 wpConsole.y = wp.rcNormalPosition.top;
\r
2337 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2338 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2341 if (analysisDialog) {
\r
2342 GetWindowPlacement(analysisDialog, &wp);
\r
2343 analysisX = wp.rcNormalPosition.left;
\r
2344 analysisY = wp.rcNormalPosition.top;
\r
2345 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2346 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2349 if (commentDialog) {
\r
2350 GetWindowPlacement(commentDialog, &wp);
\r
2351 commentX = wp.rcNormalPosition.left;
\r
2352 commentY = wp.rcNormalPosition.top;
\r
2353 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2354 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2357 if (editTagsDialog) {
\r
2358 GetWindowPlacement(editTagsDialog, &wp);
\r
2359 editTagsX = wp.rcNormalPosition.left;
\r
2360 editTagsY = wp.rcNormalPosition.top;
\r
2361 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2362 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2365 if (gameListDialog) {
\r
2366 GetWindowPlacement(gameListDialog, &wp);
\r
2367 wpGameList.x = wp.rcNormalPosition.left;
\r
2368 wpGameList.y = wp.rcNormalPosition.top;
\r
2369 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2370 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2373 /* [AS] Move history */
\r
2374 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2376 if( moveHistoryDialog ) {
\r
2377 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2378 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2379 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2380 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2381 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2384 /* [AS] Eval graph */
\r
2385 wpEvalGraph.visible = EvalGraphIsUp();
\r
2387 if( evalGraphDialog ) {
\r
2388 GetWindowPlacement(evalGraphDialog, &wp);
\r
2389 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2390 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2391 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2392 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2395 /* [AS] Engine output */
\r
2396 wpEngineOutput.visible = EngineOutputIsUp();
\r
2398 if( engineOutputDialog ) {
\r
2399 GetWindowPlacement(engineOutputDialog, &wp);
\r
2400 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2401 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2402 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2403 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2406 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2407 if (!ad->save) continue;
\r
2408 switch (ad->argType) {
\r
2411 char *p = *(char **)ad->argLoc;
\r
2412 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2413 /* Quote multiline values or \-containing values
\r
2414 with { } if possible */
\r
2415 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2417 /* Else quote with " " */
\r
2418 fprintf(f, "/%s=\"", ad->argName);
\r
2420 if (*p == '\n') fprintf(f, "\n");
\r
2421 else if (*p == '\r') fprintf(f, "\\r");
\r
2422 else if (*p == '\t') fprintf(f, "\\t");
\r
2423 else if (*p == '\b') fprintf(f, "\\b");
\r
2424 else if (*p == '\f') fprintf(f, "\\f");
\r
2425 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2426 else if (*p == '\"') fprintf(f, "\\\"");
\r
2427 else if (*p == '\\') fprintf(f, "\\\\");
\r
2431 fprintf(f, "\"\n");
\r
2437 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2440 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2443 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2446 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2449 fprintf(f, "/%s=%s\n", ad->argName,
\r
2450 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2453 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2456 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2460 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2461 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2462 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2467 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2468 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2469 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2470 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2471 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2472 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2473 (ta->effects) ? " " : "",
\r
2474 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2478 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2479 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2481 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2484 case ArgBoardSize:
\r
2485 fprintf(f, "/%s=%s\n", ad->argName,
\r
2486 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2491 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2492 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2493 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2494 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2495 ad->argName, mfp->faceName, mfp->pointSize,
\r
2496 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2497 mfp->bold ? "b" : "",
\r
2498 mfp->italic ? "i" : "",
\r
2499 mfp->underline ? "u" : "",
\r
2500 mfp->strikeout ? "s" : "");
\r
2504 case ArgCommSettings:
\r
2505 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2507 case ArgSettingsFilename: ;
\r
2515 /*---------------------------------------------------------------------------*\
\r
2517 * GDI board drawing routines
\r
2519 \*---------------------------------------------------------------------------*/
\r
2521 /* [AS] Draw square using background texture */
\r
2522 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2527 return; /* Should never happen! */
\r
2530 SetGraphicsMode( dst, GM_ADVANCED );
\r
2537 /* X reflection */
\r
2542 x.eDx = (FLOAT) dw + dx - 1;
\r
2545 SetWorldTransform( dst, &x );
\r
2548 /* Y reflection */
\r
2554 x.eDy = (FLOAT) dh + dy - 1;
\r
2556 SetWorldTransform( dst, &x );
\r
2564 x.eDx = (FLOAT) dx;
\r
2565 x.eDy = (FLOAT) dy;
\r
2568 SetWorldTransform( dst, &x );
\r
2572 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2580 SetWorldTransform( dst, &x );
\r
2582 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2585 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2587 PM_WP = (int) WhitePawn,
\r
2588 PM_WN = (int) WhiteKnight,
\r
2589 PM_WB = (int) WhiteBishop,
\r
2590 PM_WR = (int) WhiteRook,
\r
2591 PM_WQ = (int) WhiteQueen,
\r
2592 PM_WF = (int) WhiteFerz,
\r
2593 PM_WW = (int) WhiteWazir,
\r
2594 PM_WE = (int) WhiteAlfil,
\r
2595 PM_WM = (int) WhiteMan,
\r
2596 PM_WO = (int) WhiteCannon,
\r
2597 PM_WU = (int) WhiteUnicorn,
\r
2598 PM_WH = (int) WhiteNightrider,
\r
2599 PM_WA = (int) WhiteAngel,
\r
2600 PM_WC = (int) WhiteMarshall,
\r
2601 PM_WAB = (int) WhiteCardinal,
\r
2602 PM_WD = (int) WhiteDragon,
\r
2603 PM_WL = (int) WhiteLance,
\r
2604 PM_WS = (int) WhiteCobra,
\r
2605 PM_WV = (int) WhiteFalcon,
\r
2606 PM_WSG = (int) WhiteSilver,
\r
2607 PM_WG = (int) WhiteGrasshopper,
\r
2608 PM_WK = (int) WhiteKing,
\r
2609 PM_BP = (int) BlackPawn,
\r
2610 PM_BN = (int) BlackKnight,
\r
2611 PM_BB = (int) BlackBishop,
\r
2612 PM_BR = (int) BlackRook,
\r
2613 PM_BQ = (int) BlackQueen,
\r
2614 PM_BF = (int) BlackFerz,
\r
2615 PM_BW = (int) BlackWazir,
\r
2616 PM_BE = (int) BlackAlfil,
\r
2617 PM_BM = (int) BlackMan,
\r
2618 PM_BO = (int) BlackCannon,
\r
2619 PM_BU = (int) BlackUnicorn,
\r
2620 PM_BH = (int) BlackNightrider,
\r
2621 PM_BA = (int) BlackAngel,
\r
2622 PM_BC = (int) BlackMarshall,
\r
2623 PM_BG = (int) BlackGrasshopper,
\r
2624 PM_BAB = (int) BlackCardinal,
\r
2625 PM_BD = (int) BlackDragon,
\r
2626 PM_BL = (int) BlackLance,
\r
2627 PM_BS = (int) BlackCobra,
\r
2628 PM_BV = (int) BlackFalcon,
\r
2629 PM_BSG = (int) BlackSilver,
\r
2630 PM_BK = (int) BlackKing
\r
2633 static HFONT hPieceFont = NULL;
\r
2634 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2635 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2636 static int fontBitmapSquareSize = 0;
\r
2637 static char pieceToFontChar[(int) EmptySquare] =
\r
2638 { 'p', 'n', 'b', 'r', 'q',
\r
2639 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2640 'k', 'o', 'm', 'v', 't', 'w',
\r
2641 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2644 extern BOOL SetCharTable( char *table, const char * map );
\r
2645 /* [HGM] moved to backend.c */
\r
2647 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2650 BYTE r1 = GetRValue( color );
\r
2651 BYTE g1 = GetGValue( color );
\r
2652 BYTE b1 = GetBValue( color );
\r
2658 /* Create a uniform background first */
\r
2659 hbrush = CreateSolidBrush( color );
\r
2660 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2661 FillRect( hdc, &rc, hbrush );
\r
2662 DeleteObject( hbrush );
\r
2665 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2666 int steps = squareSize / 2;
\r
2669 for( i=0; i<steps; i++ ) {
\r
2670 BYTE r = r1 - (r1-r2) * i / steps;
\r
2671 BYTE g = g1 - (g1-g2) * i / steps;
\r
2672 BYTE b = b1 - (b1-b2) * i / steps;
\r
2674 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2675 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2676 FillRect( hdc, &rc, hbrush );
\r
2677 DeleteObject(hbrush);
\r
2680 else if( mode == 2 ) {
\r
2681 /* Diagonal gradient, good more or less for every piece */
\r
2682 POINT triangle[3];
\r
2683 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2684 HBRUSH hbrush_old;
\r
2685 int steps = squareSize;
\r
2688 triangle[0].x = squareSize - steps;
\r
2689 triangle[0].y = squareSize;
\r
2690 triangle[1].x = squareSize;
\r
2691 triangle[1].y = squareSize;
\r
2692 triangle[2].x = squareSize;
\r
2693 triangle[2].y = squareSize - steps;
\r
2695 for( i=0; i<steps; i++ ) {
\r
2696 BYTE r = r1 - (r1-r2) * i / steps;
\r
2697 BYTE g = g1 - (g1-g2) * i / steps;
\r
2698 BYTE b = b1 - (b1-b2) * i / steps;
\r
2700 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2701 hbrush_old = SelectObject( hdc, hbrush );
\r
2702 Polygon( hdc, triangle, 3 );
\r
2703 SelectObject( hdc, hbrush_old );
\r
2704 DeleteObject(hbrush);
\r
2709 SelectObject( hdc, hpen );
\r
2714 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2715 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2716 piece: follow the steps as explained below.
\r
2718 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2722 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2726 int backColor = whitePieceColor;
\r
2727 int foreColor = blackPieceColor;
\r
2729 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2730 backColor = appData.fontBackColorWhite;
\r
2731 foreColor = appData.fontForeColorWhite;
\r
2733 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2734 backColor = appData.fontBackColorBlack;
\r
2735 foreColor = appData.fontForeColorBlack;
\r
2739 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2741 hbm_old = SelectObject( hdc, hbm );
\r
2745 rc.right = squareSize;
\r
2746 rc.bottom = squareSize;
\r
2748 /* Step 1: background is now black */
\r
2749 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2751 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2753 pt.x = (squareSize - sz.cx) / 2;
\r
2754 pt.y = (squareSize - sz.cy) / 2;
\r
2756 SetBkMode( hdc, TRANSPARENT );
\r
2757 SetTextColor( hdc, chroma );
\r
2758 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2759 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2761 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2762 /* Step 3: the area outside the piece is filled with white */
\r
2763 // FloodFill( hdc, 0, 0, chroma );
\r
2764 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2765 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2766 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2767 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2768 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2770 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2771 but if the start point is not inside the piece we're lost!
\r
2772 There should be a better way to do this... if we could create a region or path
\r
2773 from the fill operation we would be fine for example.
\r
2775 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2776 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2778 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2779 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2780 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2782 SelectObject( dc2, bm2 );
\r
2783 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2784 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2786 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2787 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2790 DeleteObject( bm2 );
\r
2793 SetTextColor( hdc, 0 );
\r
2795 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2796 draw the piece again in black for safety.
\r
2798 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2800 SelectObject( hdc, hbm_old );
\r
2802 if( hPieceMask[index] != NULL ) {
\r
2803 DeleteObject( hPieceMask[index] );
\r
2806 hPieceMask[index] = hbm;
\r
2809 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2811 SelectObject( hdc, hbm );
\r
2814 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2815 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2816 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2818 SelectObject( dc1, hPieceMask[index] );
\r
2819 SelectObject( dc2, bm2 );
\r
2820 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2821 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2824 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2825 the piece background and deletes (makes transparent) the rest.
\r
2826 Thanks to that mask, we are free to paint the background with the greates
\r
2827 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2828 We use this, to make gradients and give the pieces a "roundish" look.
\r
2830 SetPieceBackground( hdc, backColor, 2 );
\r
2831 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2835 DeleteObject( bm2 );
\r
2838 SetTextColor( hdc, foreColor );
\r
2839 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2841 SelectObject( hdc, hbm_old );
\r
2843 if( hPieceFace[index] != NULL ) {
\r
2844 DeleteObject( hPieceFace[index] );
\r
2847 hPieceFace[index] = hbm;
\r
2850 static int TranslatePieceToFontPiece( int piece )
\r
2880 case BlackMarshall:
\r
2884 case BlackNightrider:
\r
2890 case BlackUnicorn:
\r
2894 case BlackGrasshopper:
\r
2906 case BlackCardinal:
\r
2913 case WhiteMarshall:
\r
2917 case WhiteNightrider:
\r
2923 case WhiteUnicorn:
\r
2927 case WhiteGrasshopper:
\r
2939 case WhiteCardinal:
\r
2948 void CreatePiecesFromFont()
\r
2951 HDC hdc_window = NULL;
\r
2957 if( fontBitmapSquareSize < 0 ) {
\r
2958 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2962 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2963 fontBitmapSquareSize = -1;
\r
2967 if( fontBitmapSquareSize != squareSize ) {
\r
2968 hdc_window = GetDC( hwndMain );
\r
2969 hdc = CreateCompatibleDC( hdc_window );
\r
2971 if( hPieceFont != NULL ) {
\r
2972 DeleteObject( hPieceFont );
\r
2975 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2976 hPieceMask[i] = NULL;
\r
2977 hPieceFace[i] = NULL;
\r
2983 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2984 fontHeight = appData.fontPieceSize;
\r
2987 fontHeight = (fontHeight * squareSize) / 100;
\r
2989 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2991 lf.lfEscapement = 0;
\r
2992 lf.lfOrientation = 0;
\r
2993 lf.lfWeight = FW_NORMAL;
\r
2995 lf.lfUnderline = 0;
\r
2996 lf.lfStrikeOut = 0;
\r
2997 lf.lfCharSet = DEFAULT_CHARSET;
\r
2998 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2999 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3000 lf.lfQuality = PROOF_QUALITY;
\r
3001 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3002 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3003 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3005 hPieceFont = CreateFontIndirect( &lf );
\r
3007 if( hPieceFont == NULL ) {
\r
3008 fontBitmapSquareSize = -2;
\r
3011 /* Setup font-to-piece character table */
\r
3012 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3013 /* No (or wrong) global settings, try to detect the font */
\r
3014 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3016 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3018 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3019 /* DiagramTT* family */
\r
3020 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3022 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3023 /* Fairy symbols */
\r
3024 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3026 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3027 /* Good Companion (Some characters get warped as literal :-( */
\r
3028 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3029 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3030 SetCharTable(pieceToFontChar, s);
\r
3033 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3034 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3038 /* Create bitmaps */
\r
3039 hfont_old = SelectObject( hdc, hPieceFont );
\r
3040 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3041 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3044 SelectObject( hdc, hfont_old );
\r
3046 fontBitmapSquareSize = squareSize;
\r
3050 if( hdc != NULL ) {
\r
3054 if( hdc_window != NULL ) {
\r
3055 ReleaseDC( hwndMain, hdc_window );
\r
3060 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3064 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3065 if (gameInfo.event &&
\r
3066 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3067 strcmp(name, "k80s") == 0) {
\r
3068 strcpy(name, "tim");
\r
3070 return LoadBitmap(hinst, name);
\r
3074 /* Insert a color into the program's logical palette
\r
3075 structure. This code assumes the given color is
\r
3076 the result of the RGB or PALETTERGB macro, and it
\r
3077 knows how those macros work (which is documented).
\r
3080 InsertInPalette(COLORREF color)
\r
3082 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3084 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3085 DisplayFatalError("Too many colors", 0, 1);
\r
3086 pLogPal->palNumEntries--;
\r
3090 pe->peFlags = (char) 0;
\r
3091 pe->peRed = (char) (0xFF & color);
\r
3092 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3093 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3099 InitDrawingColors()
\r
3101 if (pLogPal == NULL) {
\r
3102 /* Allocate enough memory for a logical palette with
\r
3103 * PALETTESIZE entries and set the size and version fields
\r
3104 * of the logical palette structure.
\r
3106 pLogPal = (NPLOGPALETTE)
\r
3107 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3108 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3109 pLogPal->palVersion = 0x300;
\r
3111 pLogPal->palNumEntries = 0;
\r
3113 InsertInPalette(lightSquareColor);
\r
3114 InsertInPalette(darkSquareColor);
\r
3115 InsertInPalette(whitePieceColor);
\r
3116 InsertInPalette(blackPieceColor);
\r
3117 InsertInPalette(highlightSquareColor);
\r
3118 InsertInPalette(premoveHighlightColor);
\r
3120 /* create a logical color palette according the information
\r
3121 * in the LOGPALETTE structure.
\r
3123 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3125 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3126 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3127 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3128 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3129 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3130 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3131 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3132 /* [AS] Force rendering of the font-based pieces */
\r
3133 if( fontBitmapSquareSize > 0 ) {
\r
3134 fontBitmapSquareSize = 0;
\r
3140 BoardWidth(int boardSize, int n)
\r
3141 { /* [HGM] argument n added to allow different width and height */
\r
3142 int lineGap = sizeInfo[boardSize].lineGap;
\r
3144 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3145 lineGap = appData.overrideLineGap;
\r
3148 return (n + 1) * lineGap +
\r
3149 n * sizeInfo[boardSize].squareSize;
\r
3152 /* Respond to board resize by dragging edge */
\r
3154 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3156 BoardSize newSize = NUM_SIZES - 1;
\r
3157 static int recurse = 0;
\r
3158 if (IsIconic(hwndMain)) return;
\r
3159 if (recurse > 0) return;
\r
3161 while (newSize > 0) {
\r
3162 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3163 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3164 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3167 boardSize = newSize;
\r
3168 InitDrawingSizes(boardSize, flags);
\r
3175 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3177 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3178 ChessSquare piece;
\r
3179 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3181 SIZE clockSize, messageSize;
\r
3183 char buf[MSG_SIZ];
\r
3185 HMENU hmenu = GetMenu(hwndMain);
\r
3186 RECT crect, wrect, oldRect;
\r
3188 LOGBRUSH logbrush;
\r
3190 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3191 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3193 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3194 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3196 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3197 oldRect.top = boardY;
\r
3198 oldRect.right = boardX + winWidth;
\r
3199 oldRect.bottom = boardY + winHeight;
\r
3201 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3202 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3203 squareSize = sizeInfo[boardSize].squareSize;
\r
3204 lineGap = sizeInfo[boardSize].lineGap;
\r
3205 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3207 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3208 lineGap = appData.overrideLineGap;
\r
3211 if (tinyLayout != oldTinyLayout) {
\r
3212 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3214 style &= ~WS_SYSMENU;
\r
3215 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3216 "&Minimize\tCtrl+F4");
\r
3218 style |= WS_SYSMENU;
\r
3219 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3221 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3223 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3224 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3225 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3227 DrawMenuBar(hwndMain);
\r
3230 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3231 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3233 /* Get text area sizes */
\r
3234 hdc = GetDC(hwndMain);
\r
3235 if (appData.clockMode) {
\r
3236 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3238 sprintf(buf, "White");
\r
3240 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3241 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3242 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3243 str = "We only care about the height here";
\r
3244 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3245 SelectObject(hdc, oldFont);
\r
3246 ReleaseDC(hwndMain, hdc);
\r
3248 /* Compute where everything goes */
\r
3249 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3250 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3251 logoHeight = 2*clockSize.cy;
\r
3252 leftLogoRect.left = OUTER_MARGIN;
\r
3253 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3254 leftLogoRect.top = OUTER_MARGIN;
\r
3255 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3257 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3258 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3259 rightLogoRect.top = OUTER_MARGIN;
\r
3260 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3263 whiteRect.left = leftLogoRect.right;
\r
3264 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3265 whiteRect.top = OUTER_MARGIN;
\r
3266 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3268 blackRect.right = rightLogoRect.left;
\r
3269 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3270 blackRect.top = whiteRect.top;
\r
3271 blackRect.bottom = whiteRect.bottom;
\r
3273 whiteRect.left = OUTER_MARGIN;
\r
3274 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3275 whiteRect.top = OUTER_MARGIN;
\r
3276 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3278 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3279 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3280 blackRect.top = whiteRect.top;
\r
3281 blackRect.bottom = whiteRect.bottom;
\r
3284 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3285 if (appData.showButtonBar) {
\r
3286 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3287 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3289 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3291 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3292 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3294 boardRect.left = OUTER_MARGIN;
\r
3295 boardRect.right = boardRect.left + boardWidth;
\r
3296 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3297 boardRect.bottom = boardRect.top + boardHeight;
\r
3299 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3300 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3301 oldBoardSize = boardSize;
\r
3302 oldTinyLayout = tinyLayout;
\r
3303 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3304 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3305 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3306 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3307 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3308 winHeight = winH; // without disturbing window attachments
\r
3309 GetWindowRect(hwndMain, &wrect);
\r
3310 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3311 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3313 // [HGM] placement: let attached windows follow size change.
\r
3314 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3315 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3318 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3320 /* compensate if menu bar wrapped */
\r
3321 GetClientRect(hwndMain, &crect);
\r
3322 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3323 winHeight += offby;
\r
3325 case WMSZ_TOPLEFT:
\r
3326 SetWindowPos(hwndMain, NULL,
\r
3327 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3328 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3331 case WMSZ_TOPRIGHT:
\r
3333 SetWindowPos(hwndMain, NULL,
\r
3334 wrect.left, wrect.bottom - winHeight,
\r
3335 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3338 case WMSZ_BOTTOMLEFT:
\r
3340 SetWindowPos(hwndMain, NULL,
\r
3341 wrect.right - winWidth, wrect.top,
\r
3342 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3345 case WMSZ_BOTTOMRIGHT:
\r
3349 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3350 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3355 for (i = 0; i < N_BUTTONS; i++) {
\r
3356 if (buttonDesc[i].hwnd != NULL) {
\r
3357 DestroyWindow(buttonDesc[i].hwnd);
\r
3358 buttonDesc[i].hwnd = NULL;
\r
3360 if (appData.showButtonBar) {
\r
3361 buttonDesc[i].hwnd =
\r
3362 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3363 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3364 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3365 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3366 (HMENU) buttonDesc[i].id,
\r
3367 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3369 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3370 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3371 MAKELPARAM(FALSE, 0));
\r
3373 if (buttonDesc[i].id == IDM_Pause)
\r
3374 hwndPause = buttonDesc[i].hwnd;
\r
3375 buttonDesc[i].wndproc = (WNDPROC)
\r
3376 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3379 if (gridPen != NULL) DeleteObject(gridPen);
\r
3380 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3381 if (premovePen != NULL) DeleteObject(premovePen);
\r
3382 if (lineGap != 0) {
\r
3383 logbrush.lbStyle = BS_SOLID;
\r
3384 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3386 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3387 lineGap, &logbrush, 0, NULL);
\r
3388 logbrush.lbColor = highlightSquareColor;
\r
3390 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3391 lineGap, &logbrush, 0, NULL);
\r
3393 logbrush.lbColor = premoveHighlightColor;
\r
3395 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3396 lineGap, &logbrush, 0, NULL);
\r
3398 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3399 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3400 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3401 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3402 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3403 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3404 BOARD_WIDTH * (squareSize + lineGap);
\r
3405 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3407 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3408 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3409 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3410 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3411 lineGap / 2 + (i * (squareSize + lineGap));
\r
3412 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3413 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3414 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3418 /* [HGM] Licensing requirement */
\r
3420 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3423 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3425 GothicPopUp( "", VariantNormal);
\r
3428 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3430 /* Load piece bitmaps for this board size */
\r
3431 for (i=0; i<=2; i++) {
\r
3432 for (piece = WhitePawn;
\r
3433 (int) piece < (int) BlackPawn;
\r
3434 piece = (ChessSquare) ((int) piece + 1)) {
\r
3435 if (pieceBitmap[i][piece] != NULL)
\r
3436 DeleteObject(pieceBitmap[i][piece]);
\r
3440 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3441 // Orthodox Chess pieces
\r
3442 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3443 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3444 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3446 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3447 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3451 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3452 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3454 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3456 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3457 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3458 // in Shogi, Hijack the unused Queen for Lance
\r
3459 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3460 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3461 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3463 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3464 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3465 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3468 if(squareSize <= 72 && squareSize >= 33) {
\r
3469 /* A & C are available in most sizes now */
\r
3470 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3471 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3472 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3473 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3474 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3475 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3476 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3477 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3478 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3479 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3480 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3481 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3482 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3483 } else { // Smirf-like
\r
3484 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3485 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3486 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3488 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3489 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3490 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3491 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3492 } else { // WinBoard standard
\r
3493 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3494 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3495 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3500 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3501 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3502 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3503 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3504 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3505 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3506 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3507 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3508 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3509 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3510 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3511 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3512 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3513 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3516 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3517 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3518 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3519 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3520 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3521 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3522 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3525 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3526 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3527 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3528 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3532 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3533 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3536 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3537 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3538 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3539 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3542 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3543 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3544 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3560 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3561 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3562 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3563 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3564 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3565 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3566 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3567 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3568 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3569 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3570 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3571 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3572 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3573 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3574 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3578 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3579 /* special Shogi support in this size */
\r
3580 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3581 for (piece = WhitePawn;
\r
3582 (int) piece < (int) BlackPawn;
\r
3583 piece = (ChessSquare) ((int) piece + 1)) {
\r
3584 if (pieceBitmap[i][piece] != NULL)
\r
3585 DeleteObject(pieceBitmap[i][piece]);
\r
3588 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3589 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3590 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3601 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3602 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3603 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3604 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3615 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3616 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3617 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3618 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3629 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3635 PieceBitmap(ChessSquare p, int kind)
\r
3637 if ((int) p >= (int) BlackPawn)
\r
3638 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3640 return pieceBitmap[kind][(int) p];
\r
3643 /***************************************************************/
\r
3645 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3646 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3648 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3649 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3653 SquareToPos(int row, int column, int * x, int * y)
\r
3656 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3657 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3659 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3660 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3665 DrawCoordsOnDC(HDC hdc)
\r
3667 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
3668 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
3669 char str[2] = { NULLCHAR, NULLCHAR };
\r
3670 int oldMode, oldAlign, x, y, start, i;
\r
3674 if (!appData.showCoords)
\r
3677 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3679 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3680 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3681 oldAlign = GetTextAlign(hdc);
\r
3682 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3684 y = boardRect.top + lineGap;
\r
3685 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3687 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3688 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3689 str[0] = files[start + i];
\r
3690 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3691 y += squareSize + lineGap;
\r
3694 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3696 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3697 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3698 str[0] = ranks[start + i];
\r
3699 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3700 x += squareSize + lineGap;
\r
3703 SelectObject(hdc, oldBrush);
\r
3704 SetBkMode(hdc, oldMode);
\r
3705 SetTextAlign(hdc, oldAlign);
\r
3706 SelectObject(hdc, oldFont);
\r
3710 DrawGridOnDC(HDC hdc)
\r
3714 if (lineGap != 0) {
\r
3715 oldPen = SelectObject(hdc, gridPen);
\r
3716 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3717 SelectObject(hdc, oldPen);
\r
3721 #define HIGHLIGHT_PEN 0
\r
3722 #define PREMOVE_PEN 1
\r
3725 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3728 HPEN oldPen, hPen;
\r
3729 if (lineGap == 0) return;
\r
3731 x1 = boardRect.left +
\r
3732 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3733 y1 = boardRect.top +
\r
3734 lineGap/2 + y * (squareSize + lineGap);
\r
3736 x1 = boardRect.left +
\r
3737 lineGap/2 + x * (squareSize + lineGap);
\r
3738 y1 = boardRect.top +
\r
3739 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3741 hPen = pen ? premovePen : highlightPen;
\r
3742 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3743 MoveToEx(hdc, x1, y1, NULL);
\r
3744 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3745 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3746 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3747 LineTo(hdc, x1, y1);
\r
3748 SelectObject(hdc, oldPen);
\r
3752 DrawHighlightsOnDC(HDC hdc)
\r
3755 for (i=0; i<2; i++) {
\r
3756 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3757 DrawHighlightOnDC(hdc, TRUE,
\r
3758 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3761 for (i=0; i<2; i++) {
\r
3762 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3763 premoveHighlightInfo.sq[i].y >= 0) {
\r
3764 DrawHighlightOnDC(hdc, TRUE,
\r
3765 premoveHighlightInfo.sq[i].x,
\r
3766 premoveHighlightInfo.sq[i].y,
\r
3772 /* Note: sqcolor is used only in monoMode */
\r
3773 /* Note that this code is largely duplicated in woptions.c,
\r
3774 function DrawSampleSquare, so that needs to be updated too */
\r
3776 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3778 HBITMAP oldBitmap;
\r
3782 if (appData.blindfold) return;
\r
3784 /* [AS] Use font-based pieces if needed */
\r
3785 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3786 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3787 CreatePiecesFromFont();
\r
3789 if( fontBitmapSquareSize == squareSize ) {
\r
3790 int index = TranslatePieceToFontPiece(piece);
\r
3792 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3796 squareSize, squareSize,
\r
3801 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3805 squareSize, squareSize,
\r
3814 if (appData.monoMode) {
\r
3815 SelectObject(tmphdc, PieceBitmap(piece,
\r
3816 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3817 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3818 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3820 tmpSize = squareSize;
\r
3822 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3823 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3824 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3825 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3826 x += (squareSize - minorSize)>>1;
\r
3827 y += squareSize - minorSize - 2;
\r
3828 tmpSize = minorSize;
\r
3830 if (color || appData.allWhite ) {
\r
3831 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3833 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3834 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3835 if(appData.upsideDown && color==flipView)
\r
3836 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3838 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3839 /* Use black for outline of white pieces */
\r
3840 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3841 if(appData.upsideDown && color==flipView)
\r
3842 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3844 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3846 /* Use square color for details of black pieces */
\r
3847 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3848 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3849 if(appData.upsideDown && !flipView)
\r
3850 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3852 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3854 SelectObject(hdc, oldBrush);
\r
3855 SelectObject(tmphdc, oldBitmap);
\r
3859 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3860 int GetBackTextureMode( int algo )
\r
3862 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3866 case BACK_TEXTURE_MODE_PLAIN:
\r
3867 result = 1; /* Always use identity map */
\r
3869 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3870 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3878 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3879 to handle redraws cleanly (as random numbers would always be different).
\r
3881 VOID RebuildTextureSquareInfo()
\r
3891 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3893 if( liteBackTexture != NULL ) {
\r
3894 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3895 lite_w = bi.bmWidth;
\r
3896 lite_h = bi.bmHeight;
\r
3900 if( darkBackTexture != NULL ) {
\r
3901 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3902 dark_w = bi.bmWidth;
\r
3903 dark_h = bi.bmHeight;
\r
3907 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3908 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3909 if( (col + row) & 1 ) {
\r
3911 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3912 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3913 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3914 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3919 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3920 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3921 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3922 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3929 /* [AS] Arrow highlighting support */
\r
3931 static int A_WIDTH = 5; /* Width of arrow body */
\r
3933 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3934 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3936 static double Sqr( double x )
\r
3941 static int Round( double x )
\r
3943 return (int) (x + 0.5);
\r
3946 /* Draw an arrow between two points using current settings */
\r
3947 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3950 double dx, dy, j, k, x, y;
\r
3952 if( d_x == s_x ) {
\r
3953 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3955 arrow[0].x = s_x + A_WIDTH;
\r
3958 arrow[1].x = s_x + A_WIDTH;
\r
3959 arrow[1].y = d_y - h;
\r
3961 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3962 arrow[2].y = d_y - h;
\r
3967 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3968 arrow[4].y = d_y - h;
\r
3970 arrow[5].x = s_x - A_WIDTH;
\r
3971 arrow[5].y = d_y - h;
\r
3973 arrow[6].x = s_x - A_WIDTH;
\r
3976 else if( d_y == s_y ) {
\r
3977 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3980 arrow[0].y = s_y + A_WIDTH;
\r
3982 arrow[1].x = d_x - w;
\r
3983 arrow[1].y = s_y + A_WIDTH;
\r
3985 arrow[2].x = d_x - w;
\r
3986 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3991 arrow[4].x = d_x - w;
\r
3992 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3994 arrow[5].x = d_x - w;
\r
3995 arrow[5].y = s_y - A_WIDTH;
\r
3998 arrow[6].y = s_y - A_WIDTH;
\r
4001 /* [AS] Needed a lot of paper for this! :-) */
\r
4002 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4003 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4005 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4007 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4012 arrow[0].x = Round(x - j);
\r
4013 arrow[0].y = Round(y + j*dx);
\r
4015 arrow[1].x = Round(x + j);
\r
4016 arrow[1].y = Round(y - j*dx);
\r
4019 x = (double) d_x - k;
\r
4020 y = (double) d_y - k*dy;
\r
4023 x = (double) d_x + k;
\r
4024 y = (double) d_y + k*dy;
\r
4027 arrow[2].x = Round(x + j);
\r
4028 arrow[2].y = Round(y - j*dx);
\r
4030 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4031 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4036 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4037 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4039 arrow[6].x = Round(x - j);
\r
4040 arrow[6].y = Round(y + j*dx);
\r
4043 Polygon( hdc, arrow, 7 );
\r
4046 /* [AS] Draw an arrow between two squares */
\r
4047 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4049 int s_x, s_y, d_x, d_y;
\r
4056 if( s_col == d_col && s_row == d_row ) {
\r
4060 /* Get source and destination points */
\r
4061 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4062 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4065 d_y += squareSize / 4;
\r
4067 else if( d_y < s_y ) {
\r
4068 d_y += 3 * squareSize / 4;
\r
4071 d_y += squareSize / 2;
\r
4075 d_x += squareSize / 4;
\r
4077 else if( d_x < s_x ) {
\r
4078 d_x += 3 * squareSize / 4;
\r
4081 d_x += squareSize / 2;
\r
4084 s_x += squareSize / 2;
\r
4085 s_y += squareSize / 2;
\r
4087 /* Adjust width */
\r
4088 A_WIDTH = squareSize / 14;
\r
4091 stLB.lbStyle = BS_SOLID;
\r
4092 stLB.lbColor = appData.highlightArrowColor;
\r
4095 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4096 holdpen = SelectObject( hdc, hpen );
\r
4097 hbrush = CreateBrushIndirect( &stLB );
\r
4098 holdbrush = SelectObject( hdc, hbrush );
\r
4100 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4102 SelectObject( hdc, holdpen );
\r
4103 SelectObject( hdc, holdbrush );
\r
4104 DeleteObject( hpen );
\r
4105 DeleteObject( hbrush );
\r
4108 BOOL HasHighlightInfo()
\r
4110 BOOL result = FALSE;
\r
4112 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4113 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4121 BOOL IsDrawArrowEnabled()
\r
4123 BOOL result = FALSE;
\r
4125 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4132 VOID DrawArrowHighlight( HDC hdc )
\r
4134 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4135 DrawArrowBetweenSquares( hdc,
\r
4136 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4137 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4141 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4143 HRGN result = NULL;
\r
4145 if( HasHighlightInfo() ) {
\r
4146 int x1, y1, x2, y2;
\r
4147 int sx, sy, dx, dy;
\r
4149 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4150 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4152 sx = MIN( x1, x2 );
\r
4153 sy = MIN( y1, y2 );
\r
4154 dx = MAX( x1, x2 ) + squareSize;
\r
4155 dy = MAX( y1, y2 ) + squareSize;
\r
4157 result = CreateRectRgn( sx, sy, dx, dy );
\r
4164 Warning: this function modifies the behavior of several other functions.
\r
4166 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4167 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4168 repaint is scattered all over the place, which is not good for features such as
\r
4169 "arrow highlighting" that require a full repaint of the board.
\r
4171 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4172 user interaction, when speed is not so important) but especially to avoid errors
\r
4173 in the displayed graphics.
\r
4175 In such patched places, I always try refer to this function so there is a single
\r
4176 place to maintain knowledge.
\r
4178 To restore the original behavior, just return FALSE unconditionally.
\r
4180 BOOL IsFullRepaintPreferrable()
\r
4182 BOOL result = FALSE;
\r
4184 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4185 /* Arrow may appear on the board */
\r
4193 This function is called by DrawPosition to know whether a full repaint must
\r
4196 Only DrawPosition may directly call this function, which makes use of
\r
4197 some state information. Other function should call DrawPosition specifying
\r
4198 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4200 BOOL DrawPositionNeedsFullRepaint()
\r
4202 BOOL result = FALSE;
\r
4205 Probably a slightly better policy would be to trigger a full repaint
\r
4206 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4207 but animation is fast enough that it's difficult to notice.
\r
4209 if( animInfo.piece == EmptySquare ) {
\r
4210 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4219 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4221 int row, column, x, y, square_color, piece_color;
\r
4222 ChessSquare piece;
\r
4224 HDC texture_hdc = NULL;
\r
4226 /* [AS] Initialize background textures if needed */
\r
4227 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4228 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4229 if( backTextureSquareSize != squareSize
\r
4230 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4231 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4232 backTextureSquareSize = squareSize;
\r
4233 RebuildTextureSquareInfo();
\r
4236 texture_hdc = CreateCompatibleDC( hdc );
\r
4239 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4240 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4242 SquareToPos(row, column, &x, &y);
\r
4244 piece = board[row][column];
\r
4246 square_color = ((column + row) % 2) == 1;
\r
4247 if( gameInfo.variant == VariantXiangqi ) {
\r
4248 square_color = !InPalace(row, column);
\r
4249 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4250 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4252 piece_color = (int) piece < (int) BlackPawn;
\r
4255 /* [HGM] holdings file: light square or black */
\r
4256 if(column == BOARD_LEFT-2) {
\r
4257 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4260 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4264 if(column == BOARD_RGHT + 1 ) {
\r
4265 if( row < gameInfo.holdingsSize )
\r
4268 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4272 if(column == BOARD_LEFT-1 ) /* left align */
\r
4273 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4274 else if( column == BOARD_RGHT) /* right align */
\r
4275 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4277 if (appData.monoMode) {
\r
4278 if (piece == EmptySquare) {
\r
4279 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4280 square_color ? WHITENESS : BLACKNESS);
\r
4282 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4285 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4286 /* [AS] Draw the square using a texture bitmap */
\r
4287 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4288 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4289 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4292 squareSize, squareSize,
\r
4295 backTextureSquareInfo[r][c].mode,
\r
4296 backTextureSquareInfo[r][c].x,
\r
4297 backTextureSquareInfo[r][c].y );
\r
4299 SelectObject( texture_hdc, hbm );
\r
4301 if (piece != EmptySquare) {
\r
4302 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4306 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4308 oldBrush = SelectObject(hdc, brush );
\r
4309 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4310 SelectObject(hdc, oldBrush);
\r
4311 if (piece != EmptySquare)
\r
4312 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4317 if( texture_hdc != NULL ) {
\r
4318 DeleteDC( texture_hdc );
\r
4322 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4323 void fputDW(FILE *f, int x)
\r
4325 fputc(x & 255, f);
\r
4326 fputc(x>>8 & 255, f);
\r
4327 fputc(x>>16 & 255, f);
\r
4328 fputc(x>>24 & 255, f);
\r
4331 #define MAX_CLIPS 200 /* more than enough */
\r
4334 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4336 // HBITMAP bufferBitmap;
\r
4341 int w = 100, h = 50;
\r
4343 if(logo == NULL) return;
\r
4344 // GetClientRect(hwndMain, &Rect);
\r
4345 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4346 // Rect.bottom-Rect.top+1);
\r
4347 tmphdc = CreateCompatibleDC(hdc);
\r
4348 hbm = SelectObject(tmphdc, logo);
\r
4349 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4353 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4354 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4355 SelectObject(tmphdc, hbm);
\r
4360 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4362 static Board lastReq, lastDrawn;
\r
4363 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4364 static int lastDrawnFlipView = 0;
\r
4365 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4366 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4369 HBITMAP bufferBitmap;
\r
4370 HBITMAP oldBitmap;
\r
4372 HRGN clips[MAX_CLIPS];
\r
4373 ChessSquare dragged_piece = EmptySquare;
\r
4375 /* I'm undecided on this - this function figures out whether a full
\r
4376 * repaint is necessary on its own, so there's no real reason to have the
\r
4377 * caller tell it that. I think this can safely be set to FALSE - but
\r
4378 * if we trust the callers not to request full repaints unnessesarily, then
\r
4379 * we could skip some clipping work. In other words, only request a full
\r
4380 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4381 * gamestart and similar) --Hawk
\r
4383 Boolean fullrepaint = repaint;
\r
4385 if( DrawPositionNeedsFullRepaint() ) {
\r
4386 fullrepaint = TRUE;
\r
4389 if (board == NULL) {
\r
4390 if (!lastReqValid) {
\r
4395 CopyBoard(lastReq, board);
\r
4399 if (doingSizing) {
\r
4403 if (IsIconic(hwndMain)) {
\r
4407 if (hdc == NULL) {
\r
4408 hdc = GetDC(hwndMain);
\r
4409 if (!appData.monoMode) {
\r
4410 SelectPalette(hdc, hPal, FALSE);
\r
4411 RealizePalette(hdc);
\r
4415 releaseDC = FALSE;
\r
4418 /* Create some work-DCs */
\r
4419 hdcmem = CreateCompatibleDC(hdc);
\r
4420 tmphdc = CreateCompatibleDC(hdc);
\r
4422 /* If dragging is in progress, we temporarely remove the piece */
\r
4423 /* [HGM] or temporarily decrease count if stacked */
\r
4424 /* !! Moved to before board compare !! */
\r
4425 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4426 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4427 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4428 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4429 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4431 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4432 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4433 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4435 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4438 /* Figure out which squares need updating by comparing the
\r
4439 * newest board with the last drawn board and checking if
\r
4440 * flipping has changed.
\r
4442 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4443 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4444 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4445 if (lastDrawn[row][column] != board[row][column]) {
\r
4446 SquareToPos(row, column, &x, &y);
\r
4447 clips[num_clips++] =
\r
4448 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4452 for (i=0; i<2; i++) {
\r
4453 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4454 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4455 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4456 lastDrawnHighlight.sq[i].y >= 0) {
\r
4457 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4458 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4459 clips[num_clips++] =
\r
4460 CreateRectRgn(x - lineGap, y - lineGap,
\r
4461 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4463 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4464 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4465 clips[num_clips++] =
\r
4466 CreateRectRgn(x - lineGap, y - lineGap,
\r
4467 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4471 for (i=0; i<2; i++) {
\r
4472 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4473 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4474 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4475 lastDrawnPremove.sq[i].y >= 0) {
\r
4476 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4477 lastDrawnPremove.sq[i].x, &x, &y);
\r
4478 clips[num_clips++] =
\r
4479 CreateRectRgn(x - lineGap, y - lineGap,
\r
4480 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4482 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4483 premoveHighlightInfo.sq[i].y >= 0) {
\r
4484 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4485 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4486 clips[num_clips++] =
\r
4487 CreateRectRgn(x - lineGap, y - lineGap,
\r
4488 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4493 fullrepaint = TRUE;
\r
4496 /* Create a buffer bitmap - this is the actual bitmap
\r
4497 * being written to. When all the work is done, we can
\r
4498 * copy it to the real DC (the screen). This avoids
\r
4499 * the problems with flickering.
\r
4501 GetClientRect(hwndMain, &Rect);
\r
4502 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4503 Rect.bottom-Rect.top+1);
\r
4504 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4505 if (!appData.monoMode) {
\r
4506 SelectPalette(hdcmem, hPal, FALSE);
\r
4509 /* Create clips for dragging */
\r
4510 if (!fullrepaint) {
\r
4511 if (dragInfo.from.x >= 0) {
\r
4512 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4513 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4515 if (dragInfo.start.x >= 0) {
\r
4516 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4517 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4519 if (dragInfo.pos.x >= 0) {
\r
4520 x = dragInfo.pos.x - squareSize / 2;
\r
4521 y = dragInfo.pos.y - squareSize / 2;
\r
4522 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4524 if (dragInfo.lastpos.x >= 0) {
\r
4525 x = dragInfo.lastpos.x - squareSize / 2;
\r
4526 y = dragInfo.lastpos.y - squareSize / 2;
\r
4527 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4531 /* Are we animating a move?
\r
4533 * - remove the piece from the board (temporarely)
\r
4534 * - calculate the clipping region
\r
4536 if (!fullrepaint) {
\r
4537 if (animInfo.piece != EmptySquare) {
\r
4538 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4539 x = boardRect.left + animInfo.lastpos.x;
\r
4540 y = boardRect.top + animInfo.lastpos.y;
\r
4541 x2 = boardRect.left + animInfo.pos.x;
\r
4542 y2 = boardRect.top + animInfo.pos.y;
\r
4543 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4544 /* Slight kludge. The real problem is that after AnimateMove is
\r
4545 done, the position on the screen does not match lastDrawn.
\r
4546 This currently causes trouble only on e.p. captures in
\r
4547 atomic, where the piece moves to an empty square and then
\r
4548 explodes. The old and new positions both had an empty square
\r
4549 at the destination, but animation has drawn a piece there and
\r
4550 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4551 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4555 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4556 if (num_clips == 0)
\r
4557 fullrepaint = TRUE;
\r
4559 /* Set clipping on the memory DC */
\r
4560 if (!fullrepaint) {
\r
4561 SelectClipRgn(hdcmem, clips[0]);
\r
4562 for (x = 1; x < num_clips; x++) {
\r
4563 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4564 abort(); // this should never ever happen!
\r
4568 /* Do all the drawing to the memory DC */
\r
4569 if(explodeInfo.radius) { // [HGM] atomic
\r
4571 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4572 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4573 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4574 x += squareSize/2;
\r
4575 y += squareSize/2;
\r
4576 if(!fullrepaint) {
\r
4577 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4578 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4580 DrawGridOnDC(hdcmem);
\r
4581 DrawHighlightsOnDC(hdcmem);
\r
4582 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4583 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4584 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4585 SelectObject(hdcmem, oldBrush);
\r
4587 DrawGridOnDC(hdcmem);
\r
4588 DrawHighlightsOnDC(hdcmem);
\r
4589 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4592 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4593 if(appData.autoLogo) {
\r
4595 switch(gameMode) { // pick logos based on game mode
\r
4596 case IcsObserving:
\r
4597 whiteLogo = second.programLogo; // ICS logo
\r
4598 blackLogo = second.programLogo;
\r
4601 case IcsPlayingWhite:
\r
4602 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4603 blackLogo = second.programLogo; // ICS logo
\r
4605 case IcsPlayingBlack:
\r
4606 whiteLogo = second.programLogo; // ICS logo
\r
4607 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4609 case TwoMachinesPlay:
\r
4610 if(first.twoMachinesColor[0] == 'b') {
\r
4611 whiteLogo = second.programLogo;
\r
4612 blackLogo = first.programLogo;
\r
4615 case MachinePlaysWhite:
\r
4616 blackLogo = userLogo;
\r
4618 case MachinePlaysBlack:
\r
4619 whiteLogo = userLogo;
\r
4620 blackLogo = first.programLogo;
\r
4623 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4624 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4627 if( appData.highlightMoveWithArrow ) {
\r
4628 DrawArrowHighlight(hdcmem);
\r
4631 DrawCoordsOnDC(hdcmem);
\r
4633 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4634 /* to make sure lastDrawn contains what is actually drawn */
\r
4636 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4637 if (dragged_piece != EmptySquare) {
\r
4638 /* [HGM] or restack */
\r
4639 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4640 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4642 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4643 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4644 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4645 x = dragInfo.pos.x - squareSize / 2;
\r
4646 y = dragInfo.pos.y - squareSize / 2;
\r
4647 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4648 ((int) dragged_piece < (int) BlackPawn),
\r
4649 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4652 /* Put the animated piece back into place and draw it */
\r
4653 if (animInfo.piece != EmptySquare) {
\r
4654 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4655 x = boardRect.left + animInfo.pos.x;
\r
4656 y = boardRect.top + animInfo.pos.y;
\r
4657 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4658 ((int) animInfo.piece < (int) BlackPawn),
\r
4659 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4662 /* Release the bufferBitmap by selecting in the old bitmap
\r
4663 * and delete the memory DC
\r
4665 SelectObject(hdcmem, oldBitmap);
\r
4668 /* Set clipping on the target DC */
\r
4669 if (!fullrepaint) {
\r
4670 SelectClipRgn(hdc, clips[0]);
\r
4671 for (x = 1; x < num_clips; x++) {
\r
4672 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4673 abort(); // this should never ever happen!
\r
4677 /* Copy the new bitmap onto the screen in one go.
\r
4678 * This way we avoid any flickering
\r
4680 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4681 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4682 boardRect.right - boardRect.left,
\r
4683 boardRect.bottom - boardRect.top,
\r
4684 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4685 if(saveDiagFlag) {
\r
4686 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4687 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4689 GetObject(bufferBitmap, sizeof(b), &b);
\r
4690 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4691 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4692 bih.biWidth = b.bmWidth;
\r
4693 bih.biHeight = b.bmHeight;
\r
4695 bih.biBitCount = b.bmBitsPixel;
\r
4696 bih.biCompression = 0;
\r
4697 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4698 bih.biXPelsPerMeter = 0;
\r
4699 bih.biYPelsPerMeter = 0;
\r
4700 bih.biClrUsed = 0;
\r
4701 bih.biClrImportant = 0;
\r
4702 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4703 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4704 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4705 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4707 wb = b.bmWidthBytes;
\r
4709 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4710 int k = ((int*) pData)[i];
\r
4711 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4712 if(j >= 16) break;
\r
4714 if(j >= nrColors) nrColors = j+1;
\r
4716 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4718 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4719 for(w=0; w<(wb>>2); w+=2) {
\r
4720 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4721 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4722 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4723 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4724 pData[p++] = m | j<<4;
\r
4726 while(p&3) pData[p++] = 0;
\r
4729 wb = ((wb+31)>>5)<<2;
\r
4731 // write BITMAPFILEHEADER
\r
4732 fprintf(diagFile, "BM");
\r
4733 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4734 fputDW(diagFile, 0);
\r
4735 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4736 // write BITMAPINFOHEADER
\r
4737 fputDW(diagFile, 40);
\r
4738 fputDW(diagFile, b.bmWidth);
\r
4739 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4740 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4741 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\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 fputDW(diagFile, 0);
\r
4748 // write color table
\r
4750 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4751 // write bitmap data
\r
4752 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4753 fputc(pData[i], diagFile);
\r
4757 SelectObject(tmphdc, oldBitmap);
\r
4759 /* Massive cleanup */
\r
4760 for (x = 0; x < num_clips; x++)
\r
4761 DeleteObject(clips[x]);
\r
4764 DeleteObject(bufferBitmap);
\r
4767 ReleaseDC(hwndMain, hdc);
\r
4769 if (lastDrawnFlipView != flipView) {
\r
4771 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4773 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4776 /* CopyBoard(lastDrawn, board);*/
\r
4777 lastDrawnHighlight = highlightInfo;
\r
4778 lastDrawnPremove = premoveHighlightInfo;
\r
4779 lastDrawnFlipView = flipView;
\r
4780 lastDrawnValid = 1;
\r
4783 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4788 saveDiagFlag = 1; diagFile = f;
\r
4789 HDCDrawPosition(NULL, TRUE, NULL);
\r
4793 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4800 /*---------------------------------------------------------------------------*\
\r
4801 | CLIENT PAINT PROCEDURE
\r
4802 | This is the main event-handler for the WM_PAINT message.
\r
4804 \*---------------------------------------------------------------------------*/
\r
4806 PaintProc(HWND hwnd)
\r
4812 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4813 if (IsIconic(hwnd)) {
\r
4814 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4816 if (!appData.monoMode) {
\r
4817 SelectPalette(hdc, hPal, FALSE);
\r
4818 RealizePalette(hdc);
\r
4820 HDCDrawPosition(hdc, 1, NULL);
\r
4822 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4823 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4824 ETO_CLIPPED|ETO_OPAQUE,
\r
4825 &messageRect, messageText, strlen(messageText), NULL);
\r
4826 SelectObject(hdc, oldFont);
\r
4827 DisplayBothClocks();
\r
4829 EndPaint(hwnd,&ps);
\r
4837 * If the user selects on a border boundary, return -1; if off the board,
\r
4838 * return -2. Otherwise map the event coordinate to the square.
\r
4839 * The offset boardRect.left or boardRect.top must already have been
\r
4840 * subtracted from x.
\r
4842 int EventToSquare(x, limit)
\r
4850 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4852 x /= (squareSize + lineGap);
\r
4864 DropEnable dropEnables[] = {
\r
4865 { 'P', DP_Pawn, "Pawn" },
\r
4866 { 'N', DP_Knight, "Knight" },
\r
4867 { 'B', DP_Bishop, "Bishop" },
\r
4868 { 'R', DP_Rook, "Rook" },
\r
4869 { 'Q', DP_Queen, "Queen" },
\r
4873 SetupDropMenu(HMENU hmenu)
\r
4875 int i, count, enable;
\r
4877 extern char white_holding[], black_holding[];
\r
4878 char item[MSG_SIZ];
\r
4880 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4881 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4882 dropEnables[i].piece);
\r
4884 while (p && *p++ == dropEnables[i].piece) count++;
\r
4885 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4886 enable = count > 0 || !appData.testLegality
\r
4887 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4888 && !appData.icsActive);
\r
4889 ModifyMenu(hmenu, dropEnables[i].command,
\r
4890 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4891 dropEnables[i].command, item);
\r
4895 void DragPieceBegin(int x, int y)
\r
4897 dragInfo.lastpos.x = boardRect.left + x;
\r
4898 dragInfo.lastpos.y = boardRect.top + y;
\r
4899 dragInfo.from.x = fromX;
\r
4900 dragInfo.from.y = fromY;
\r
4901 dragInfo.start = dragInfo.from;
\r
4902 SetCapture(hwndMain);
\r
4905 void DragPieceEnd(int x, int y)
\r
4908 dragInfo.start.x = dragInfo.start.y = -1;
\r
4909 dragInfo.from = dragInfo.start;
\r
4910 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4913 /* Event handler for mouse messages */
\r
4915 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4919 static int recursive = 0;
\r
4921 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4924 if (message == WM_MBUTTONUP) {
\r
4925 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4926 to the middle button: we simulate pressing the left button too!
\r
4928 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4929 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4935 pt.x = LOWORD(lParam);
\r
4936 pt.y = HIWORD(lParam);
\r
4937 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4938 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4939 if (!flipView && y >= 0) {
\r
4940 y = BOARD_HEIGHT - 1 - y;
\r
4942 if (flipView && x >= 0) {
\r
4943 x = BOARD_WIDTH - 1 - x;
\r
4946 switch (message) {
\r
4947 case WM_LBUTTONDOWN:
\r
4948 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4949 if (gameMode == EditPosition) {
\r
4950 SetWhiteToPlayEvent();
\r
4951 } else if (gameMode == IcsPlayingBlack ||
\r
4952 gameMode == MachinePlaysWhite) {
\r
4954 } else if (gameMode == EditGame) {
\r
4955 AdjustClock(flipClock, -1);
\r
4957 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4958 if (gameMode == EditPosition) {
\r
4959 SetBlackToPlayEvent();
\r
4960 } else if (gameMode == IcsPlayingWhite ||
\r
4961 gameMode == MachinePlaysBlack) {
\r
4963 } else if (gameMode == EditGame) {
\r
4964 AdjustClock(!flipClock, -1);
\r
4967 dragInfo.start.x = dragInfo.start.y = -1;
\r
4968 dragInfo.from = dragInfo.start;
\r
4969 if(fromX == -1 && frozen) { // not sure where this is for
\r
4970 fromX = fromY = -1;
\r
4971 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4974 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4975 DrawPosition(TRUE, NULL);
\r
4978 case WM_LBUTTONUP:
\r
4979 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4980 DrawPosition(TRUE, NULL);
\r
4983 case WM_MOUSEMOVE:
\r
4984 if ((appData.animateDragging || appData.highlightDragging)
\r
4985 && (wParam & MK_LBUTTON)
\r
4986 && dragInfo.from.x >= 0)
\r
4988 BOOL full_repaint = FALSE;
\r
4990 if (appData.animateDragging) {
\r
4991 dragInfo.pos = pt;
\r
4993 if (appData.highlightDragging) {
\r
4994 SetHighlights(fromX, fromY, x, y);
\r
4995 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4996 full_repaint = TRUE;
\r
5000 DrawPosition( full_repaint, NULL);
\r
5002 dragInfo.lastpos = dragInfo.pos;
\r
5006 case WM_MOUSEWHEEL: // [DM]
\r
5007 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5008 /* Mouse Wheel is being rolled forward
\r
5009 * Play moves forward
\r
5011 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5012 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5013 /* Mouse Wheel is being rolled backward
\r
5014 * Play moves backward
\r
5016 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5017 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5021 case WM_MBUTTONDOWN:
\r
5022 case WM_RBUTTONDOWN:
\r
5025 fromX = fromY = -1;
\r
5026 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5027 dragInfo.start.x = dragInfo.start.y = -1;
\r
5028 dragInfo.from = dragInfo.start;
\r
5029 dragInfo.lastpos = dragInfo.pos;
\r
5030 if (appData.highlightDragging) {
\r
5031 ClearHighlights();
\r
5034 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5035 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5036 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5037 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5038 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5041 DrawPosition(TRUE, NULL);
\r
5043 switch (gameMode) {
\r
5044 case EditPosition:
\r
5045 case IcsExamining:
\r
5046 if (x < 0 || y < 0) break;
\r
5049 if (message == WM_MBUTTONDOWN) {
\r
5050 buttonCount = 3; /* even if system didn't think so */
\r
5051 if (wParam & MK_SHIFT)
\r
5052 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5054 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5055 } else { /* message == WM_RBUTTONDOWN */
\r
5056 /* Just have one menu, on the right button. Windows users don't
\r
5057 think to try the middle one, and sometimes other software steals
\r
5058 it, or it doesn't really exist. */
\r
5059 if(gameInfo.variant != VariantShogi)
\r
5060 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5062 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5065 case IcsPlayingWhite:
\r
5066 case IcsPlayingBlack:
\r
5068 case MachinePlaysWhite:
\r
5069 case MachinePlaysBlack:
\r
5070 if (appData.testLegality &&
\r
5071 gameInfo.variant != VariantBughouse &&
\r
5072 gameInfo.variant != VariantCrazyhouse) break;
\r
5073 if (x < 0 || y < 0) break;
\r
5076 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5077 SetupDropMenu(hmenu);
\r
5078 MenuPopup(hwnd, pt, hmenu, -1);
\r
5089 /* Preprocess messages for buttons in main window */
\r
5091 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5093 int id = GetWindowLong(hwnd, GWL_ID);
\r
5096 for (i=0; i<N_BUTTONS; i++) {
\r
5097 if (buttonDesc[i].id == id) break;
\r
5099 if (i == N_BUTTONS) return 0;
\r
5100 switch (message) {
\r
5105 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5106 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5113 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5116 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5117 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5118 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5119 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5121 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5123 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5124 PopUpMoveDialog((char)wParam);
\r
5130 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5133 /* Process messages for Promotion dialog box */
\r
5135 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5139 switch (message) {
\r
5140 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5141 /* Center the dialog over the application window */
\r
5142 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5143 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5144 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5145 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5146 SW_SHOW : SW_HIDE);
\r
5147 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5148 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5149 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5150 PieceToChar(WhiteAngel) != '~') ||
\r
5151 (PieceToChar(BlackAngel) >= 'A' &&
\r
5152 PieceToChar(BlackAngel) != '~') ) ?
\r
5153 SW_SHOW : SW_HIDE);
\r
5154 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5155 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5156 PieceToChar(WhiteMarshall) != '~') ||
\r
5157 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5158 PieceToChar(BlackMarshall) != '~') ) ?
\r
5159 SW_SHOW : SW_HIDE);
\r
5160 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5161 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5162 gameInfo.variant != VariantShogi ?
\r
5163 SW_SHOW : SW_HIDE);
\r
5164 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5165 gameInfo.variant != VariantShogi ?
\r
5166 SW_SHOW : SW_HIDE);
\r
5167 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5168 gameInfo.variant == VariantShogi ?
\r
5169 SW_SHOW : SW_HIDE);
\r
5170 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5171 gameInfo.variant == VariantShogi ?
\r
5172 SW_SHOW : SW_HIDE);
\r
5173 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5174 gameInfo.variant == VariantSuper ?
\r
5175 SW_SHOW : SW_HIDE);
\r
5178 case WM_COMMAND: /* message: received a command */
\r
5179 switch (LOWORD(wParam)) {
\r
5181 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5182 ClearHighlights();
\r
5183 DrawPosition(FALSE, NULL);
\r
5186 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5189 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5192 promoChar = PieceToChar(BlackRook);
\r
5195 promoChar = PieceToChar(BlackBishop);
\r
5197 case PB_Chancellor:
\r
5198 promoChar = PieceToChar(BlackMarshall);
\r
5200 case PB_Archbishop:
\r
5201 promoChar = PieceToChar(BlackAngel);
\r
5204 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5209 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5210 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5211 only show the popup when we are already sure the move is valid or
\r
5212 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5213 will figure out it is a promotion from the promoChar. */
\r
5214 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5215 fromX = fromY = -1;
\r
5216 if (!appData.highlightLastMove) {
\r
5217 ClearHighlights();
\r
5218 DrawPosition(FALSE, NULL);
\r
5225 /* Pop up promotion dialog */
\r
5227 PromotionPopup(HWND hwnd)
\r
5231 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5232 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5233 hwnd, (DLGPROC)lpProc);
\r
5234 FreeProcInstance(lpProc);
\r
5240 DrawPosition(TRUE, NULL);
\r
5241 PromotionPopup(hwndMain);
\r
5244 /* Toggle ShowThinking */
\r
5246 ToggleShowThinking()
\r
5248 appData.showThinking = !appData.showThinking;
\r
5249 ShowThinkingEvent();
\r
5253 LoadGameDialog(HWND hwnd, char* title)
\r
5257 char fileTitle[MSG_SIZ];
\r
5258 f = OpenFileDialog(hwnd, "rb", "",
\r
5259 appData.oldSaveStyle ? "gam" : "pgn",
\r
5261 title, &number, fileTitle, NULL);
\r
5263 cmailMsgLoaded = FALSE;
\r
5264 if (number == 0) {
\r
5265 int error = GameListBuild(f);
\r
5267 DisplayError("Cannot build game list", error);
\r
5268 } else if (!ListEmpty(&gameList) &&
\r
5269 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5270 GameListPopUp(f, fileTitle);
\r
5273 GameListDestroy();
\r
5276 LoadGame(f, number, fileTitle, FALSE);
\r
5280 void UpdateICSWidth(HWND hText)
\r
5285 HFONT hfont, hold_font;
\r
5286 LONG old_width, new_width;
\r
5288 // get the text metrics
\r
5289 hdc = GetDC(hText);
\r
5290 hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);
\r
5291 hold_font = SelectObject(hdc, hfont);
\r
5292 GetTextMetrics(hdc, &tm);
\r
5293 SelectObject(hdc, hold_font);
\r
5294 DeleteObject(hfont);
\r
5295 ReleaseDC(hText, hdc);
\r
5297 // get the rectangle
\r
5298 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5300 // update the width
\r
5301 new_width = (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5302 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5303 if (new_width != old_width)
\r
5305 ics_update_width(new_width);
\r
5306 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5311 ChangedConsoleFont()
\r
5314 CHARRANGE tmpsel, sel;
\r
5315 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5316 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5317 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5320 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5321 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5322 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5323 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5324 * size. This was undocumented in the version of MSVC++ that I had
\r
5325 * when I wrote the code, but is apparently documented now.
\r
5327 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5328 cfmt.bCharSet = f->lf.lfCharSet;
\r
5329 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5330 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5331 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5332 /* Why are the following seemingly needed too? */
\r
5333 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5334 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5335 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5337 tmpsel.cpMax = -1; /*999999?*/
\r
5338 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5339 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5340 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5341 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5343 paraf.cbSize = sizeof(paraf);
\r
5344 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5345 paraf.dxStartIndent = 0;
\r
5346 paraf.dxOffset = WRAP_INDENT;
\r
5347 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5348 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5349 UpdateICSWidth(hText);
\r
5352 /*---------------------------------------------------------------------------*\
\r
5354 * Window Proc for main window
\r
5356 \*---------------------------------------------------------------------------*/
\r
5358 /* Process messages for main window, etc. */
\r
5360 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5363 int wmId, wmEvent;
\r
5367 char fileTitle[MSG_SIZ];
\r
5368 char buf[MSG_SIZ];
\r
5369 static SnapData sd;
\r
5371 switch (message) {
\r
5373 case WM_PAINT: /* message: repaint portion of window */
\r
5377 case WM_ERASEBKGND:
\r
5378 if (IsIconic(hwnd)) {
\r
5379 /* Cheat; change the message */
\r
5380 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5382 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5386 case WM_LBUTTONDOWN:
\r
5387 case WM_MBUTTONDOWN:
\r
5388 case WM_RBUTTONDOWN:
\r
5389 case WM_LBUTTONUP:
\r
5390 case WM_MBUTTONUP:
\r
5391 case WM_RBUTTONUP:
\r
5392 case WM_MOUSEMOVE:
\r
5393 case WM_MOUSEWHEEL:
\r
5394 MouseEvent(hwnd, message, wParam, lParam);
\r
5397 JAWS_KB_NAVIGATION
\r
5401 JAWS_ALT_INTERCEPT
\r
5403 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5404 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5405 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5406 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5408 SendMessage(h, message, wParam, lParam);
\r
5409 } else if(lParam != KF_REPEAT) {
\r
5410 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5411 PopUpMoveDialog((char)wParam);
\r
5412 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5413 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5418 case WM_PALETTECHANGED:
\r
5419 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5421 HDC hdc = GetDC(hwndMain);
\r
5422 SelectPalette(hdc, hPal, TRUE);
\r
5423 nnew = RealizePalette(hdc);
\r
5425 paletteChanged = TRUE;
\r
5426 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5428 ReleaseDC(hwnd, hdc);
\r
5432 case WM_QUERYNEWPALETTE:
\r
5433 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5435 HDC hdc = GetDC(hwndMain);
\r
5436 paletteChanged = FALSE;
\r
5437 SelectPalette(hdc, hPal, FALSE);
\r
5438 nnew = RealizePalette(hdc);
\r
5440 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5442 ReleaseDC(hwnd, hdc);
\r
5447 case WM_COMMAND: /* message: command from application menu */
\r
5448 wmId = LOWORD(wParam);
\r
5449 wmEvent = HIWORD(wParam);
\r
5454 SAY("new game enter a move to play against the computer with white");
\r
5457 case IDM_NewGameFRC:
\r
5458 if( NewGameFRC() == 0 ) {
\r
5463 case IDM_NewVariant:
\r
5464 NewVariantPopup(hwnd);
\r
5467 case IDM_LoadGame:
\r
5468 LoadGameDialog(hwnd, "Load Game from File");
\r
5471 case IDM_LoadNextGame:
\r
5475 case IDM_LoadPrevGame:
\r
5479 case IDM_ReloadGame:
\r
5483 case IDM_LoadPosition:
\r
5484 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5485 Reset(FALSE, TRUE);
\r
5488 f = OpenFileDialog(hwnd, "rb", "",
\r
5489 appData.oldSaveStyle ? "pos" : "fen",
\r
5491 "Load Position from File", &number, fileTitle, NULL);
\r
5493 LoadPosition(f, number, fileTitle);
\r
5497 case IDM_LoadNextPosition:
\r
5498 ReloadPosition(1);
\r
5501 case IDM_LoadPrevPosition:
\r
5502 ReloadPosition(-1);
\r
5505 case IDM_ReloadPosition:
\r
5506 ReloadPosition(0);
\r
5509 case IDM_SaveGame:
\r
5510 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5511 f = OpenFileDialog(hwnd, "a", defName,
\r
5512 appData.oldSaveStyle ? "gam" : "pgn",
\r
5514 "Save Game to File", NULL, fileTitle, NULL);
\r
5516 SaveGame(f, 0, "");
\r
5520 case IDM_SavePosition:
\r
5521 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5522 f = OpenFileDialog(hwnd, "a", defName,
\r
5523 appData.oldSaveStyle ? "pos" : "fen",
\r
5525 "Save Position to File", NULL, fileTitle, NULL);
\r
5527 SavePosition(f, 0, "");
\r
5531 case IDM_SaveDiagram:
\r
5532 defName = "diagram";
\r
5533 f = OpenFileDialog(hwnd, "wb", defName,
\r
5536 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5542 case IDM_CopyGame:
\r
5543 CopyGameToClipboard();
\r
5546 case IDM_PasteGame:
\r
5547 PasteGameFromClipboard();
\r
5550 case IDM_CopyGameListToClipboard:
\r
5551 CopyGameListToClipboard();
\r
5554 /* [AS] Autodetect FEN or PGN data */
\r
5555 case IDM_PasteAny:
\r
5556 PasteGameOrFENFromClipboard();
\r
5559 /* [AS] Move history */
\r
5560 case IDM_ShowMoveHistory:
\r
5561 if( MoveHistoryIsUp() ) {
\r
5562 MoveHistoryPopDown();
\r
5565 MoveHistoryPopUp();
\r
5569 /* [AS] Eval graph */
\r
5570 case IDM_ShowEvalGraph:
\r
5571 if( EvalGraphIsUp() ) {
\r
5572 EvalGraphPopDown();
\r
5576 SetFocus(hwndMain);
\r
5580 /* [AS] Engine output */
\r
5581 case IDM_ShowEngineOutput:
\r
5582 if( EngineOutputIsUp() ) {
\r
5583 EngineOutputPopDown();
\r
5586 EngineOutputPopUp();
\r
5590 /* [AS] User adjudication */
\r
5591 case IDM_UserAdjudication_White:
\r
5592 UserAdjudicationEvent( +1 );
\r
5595 case IDM_UserAdjudication_Black:
\r
5596 UserAdjudicationEvent( -1 );
\r
5599 case IDM_UserAdjudication_Draw:
\r
5600 UserAdjudicationEvent( 0 );
\r
5603 /* [AS] Game list options dialog */
\r
5604 case IDM_GameListOptions:
\r
5605 GameListOptions();
\r
5612 case IDM_CopyPosition:
\r
5613 CopyFENToClipboard();
\r
5616 case IDM_PastePosition:
\r
5617 PasteFENFromClipboard();
\r
5620 case IDM_MailMove:
\r
5624 case IDM_ReloadCMailMsg:
\r
5625 Reset(TRUE, TRUE);
\r
5626 ReloadCmailMsgEvent(FALSE);
\r
5629 case IDM_Minimize:
\r
5630 ShowWindow(hwnd, SW_MINIMIZE);
\r
5637 case IDM_MachineWhite:
\r
5638 MachineWhiteEvent();
\r
5640 * refresh the tags dialog only if it's visible
\r
5642 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5644 tags = PGNTags(&gameInfo);
\r
5645 TagsPopUp(tags, CmailMsg());
\r
5648 SAY("computer starts playing white");
\r
5651 case IDM_MachineBlack:
\r
5652 MachineBlackEvent();
\r
5654 * refresh the tags dialog only if it's visible
\r
5656 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5658 tags = PGNTags(&gameInfo);
\r
5659 TagsPopUp(tags, CmailMsg());
\r
5662 SAY("computer starts playing black");
\r
5665 case IDM_TwoMachines:
\r
5666 TwoMachinesEvent();
\r
5668 * refresh the tags dialog only if it's visible
\r
5670 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5672 tags = PGNTags(&gameInfo);
\r
5673 TagsPopUp(tags, CmailMsg());
\r
5676 SAY("programs start playing each other");
\r
5679 case IDM_AnalysisMode:
\r
5680 if (!first.analysisSupport) {
\r
5681 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5682 DisplayError(buf, 0);
\r
5684 SAY("analyzing current position");
\r
5685 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5686 if (appData.icsActive) {
\r
5687 if (gameMode != IcsObserving) {
\r
5688 sprintf(buf, "You are not observing a game");
\r
5689 DisplayError(buf, 0);
\r
5690 /* secure check */
\r
5691 if (appData.icsEngineAnalyze) {
\r
5692 if (appData.debugMode)
\r
5693 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5694 ExitAnalyzeMode();
\r
5700 /* if enable, user want disable icsEngineAnalyze */
\r
5701 if (appData.icsEngineAnalyze) {
\r
5702 ExitAnalyzeMode();
\r
5706 appData.icsEngineAnalyze = TRUE;
\r
5707 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5710 if (!appData.showThinking) ToggleShowThinking();
\r
5711 AnalyzeModeEvent();
\r
5715 case IDM_AnalyzeFile:
\r
5716 if (!first.analysisSupport) {
\r
5717 char buf[MSG_SIZ];
\r
5718 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5719 DisplayError(buf, 0);
\r
5721 if (!appData.showThinking) ToggleShowThinking();
\r
5722 AnalyzeFileEvent();
\r
5723 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5724 AnalysisPeriodicEvent(1);
\r
5728 case IDM_IcsClient:
\r
5732 case IDM_EditGame:
\r
5737 case IDM_EditPosition:
\r
5738 EditPositionEvent();
\r
5739 SAY("to set up a position type a FEN");
\r
5742 case IDM_Training:
\r
5746 case IDM_ShowGameList:
\r
5747 ShowGameListProc();
\r
5750 case IDM_EditTags:
\r
5754 case IDM_EditComment:
\r
5755 if (commentDialogUp && editComment) {
\r
5758 EditCommentEvent();
\r
5778 case IDM_CallFlag:
\r
5798 case IDM_StopObserving:
\r
5799 StopObservingEvent();
\r
5802 case IDM_StopExamining:
\r
5803 StopExaminingEvent();
\r
5806 case IDM_TypeInMove:
\r
5807 PopUpMoveDialog('\000');
\r
5810 case IDM_TypeInName:
\r
5811 PopUpNameDialog('\000');
\r
5814 case IDM_Backward:
\r
5816 SetFocus(hwndMain);
\r
5823 SetFocus(hwndMain);
\r
5828 SetFocus(hwndMain);
\r
5833 SetFocus(hwndMain);
\r
5840 case IDM_TruncateGame:
\r
5841 TruncateGameEvent();
\r
5848 case IDM_RetractMove:
\r
5849 RetractMoveEvent();
\r
5852 case IDM_FlipView:
\r
5853 flipView = !flipView;
\r
5854 DrawPosition(FALSE, NULL);
\r
5857 case IDM_FlipClock:
\r
5858 flipClock = !flipClock;
\r
5859 DisplayBothClocks();
\r
5860 DrawPosition(FALSE, NULL);
\r
5863 case IDM_MuteSounds:
\r
5864 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5865 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5866 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5869 case IDM_GeneralOptions:
\r
5870 GeneralOptionsPopup(hwnd);
\r
5871 DrawPosition(TRUE, NULL);
\r
5874 case IDM_BoardOptions:
\r
5875 BoardOptionsPopup(hwnd);
\r
5878 case IDM_EnginePlayOptions:
\r
5879 EnginePlayOptionsPopup(hwnd);
\r
5882 case IDM_Engine1Options:
\r
5883 EngineOptionsPopup(hwnd, &first);
\r
5886 case IDM_Engine2Options:
\r
5887 EngineOptionsPopup(hwnd, &second);
\r
5890 case IDM_OptionsUCI:
\r
5891 UciOptionsPopup(hwnd);
\r
5894 case IDM_IcsOptions:
\r
5895 IcsOptionsPopup(hwnd);
\r
5899 FontsOptionsPopup(hwnd);
\r
5903 SoundOptionsPopup(hwnd);
\r
5906 case IDM_CommPort:
\r
5907 CommPortOptionsPopup(hwnd);
\r
5910 case IDM_LoadOptions:
\r
5911 LoadOptionsPopup(hwnd);
\r
5914 case IDM_SaveOptions:
\r
5915 SaveOptionsPopup(hwnd);
\r
5918 case IDM_TimeControl:
\r
5919 TimeControlOptionsPopup(hwnd);
\r
5922 case IDM_SaveSettings:
\r
5923 SaveSettings(settingsFileName);
\r
5926 case IDM_SaveSettingsOnExit:
\r
5927 saveSettingsOnExit = !saveSettingsOnExit;
\r
5928 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5929 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5930 MF_CHECKED : MF_UNCHECKED));
\r
5941 case IDM_AboutGame:
\r
5946 appData.debugMode = !appData.debugMode;
\r
5947 if (appData.debugMode) {
\r
5948 char dir[MSG_SIZ];
\r
5949 GetCurrentDirectory(MSG_SIZ, dir);
\r
5950 SetCurrentDirectory(installDir);
\r
5951 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5952 SetCurrentDirectory(dir);
\r
5953 setbuf(debugFP, NULL);
\r
5960 case IDM_HELPCONTENTS:
\r
5961 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5962 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5963 MessageBox (GetFocus(),
\r
5964 "Unable to activate help",
\r
5965 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5969 case IDM_HELPSEARCH:
\r
5970 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5971 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5972 MessageBox (GetFocus(),
\r
5973 "Unable to activate help",
\r
5974 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5978 case IDM_HELPHELP:
\r
5979 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5980 MessageBox (GetFocus(),
\r
5981 "Unable to activate help",
\r
5982 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5987 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5989 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5990 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5991 FreeProcInstance(lpProc);
\r
5994 case IDM_DirectCommand1:
\r
5995 AskQuestionEvent("Direct Command",
\r
5996 "Send to chess program:", "", "1");
\r
5998 case IDM_DirectCommand2:
\r
5999 AskQuestionEvent("Direct Command",
\r
6000 "Send to second chess program:", "", "2");
\r
6003 case EP_WhitePawn:
\r
6004 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6005 fromX = fromY = -1;
\r
6008 case EP_WhiteKnight:
\r
6009 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6010 fromX = fromY = -1;
\r
6013 case EP_WhiteBishop:
\r
6014 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6015 fromX = fromY = -1;
\r
6018 case EP_WhiteRook:
\r
6019 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6020 fromX = fromY = -1;
\r
6023 case EP_WhiteQueen:
\r
6024 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6025 fromX = fromY = -1;
\r
6028 case EP_WhiteFerz:
\r
6029 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6030 fromX = fromY = -1;
\r
6033 case EP_WhiteWazir:
\r
6034 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6035 fromX = fromY = -1;
\r
6038 case EP_WhiteAlfil:
\r
6039 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6040 fromX = fromY = -1;
\r
6043 case EP_WhiteCannon:
\r
6044 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6045 fromX = fromY = -1;
\r
6048 case EP_WhiteCardinal:
\r
6049 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6050 fromX = fromY = -1;
\r
6053 case EP_WhiteMarshall:
\r
6054 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6055 fromX = fromY = -1;
\r
6058 case EP_WhiteKing:
\r
6059 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6060 fromX = fromY = -1;
\r
6063 case EP_BlackPawn:
\r
6064 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6065 fromX = fromY = -1;
\r
6068 case EP_BlackKnight:
\r
6069 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6070 fromX = fromY = -1;
\r
6073 case EP_BlackBishop:
\r
6074 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6075 fromX = fromY = -1;
\r
6078 case EP_BlackRook:
\r
6079 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6080 fromX = fromY = -1;
\r
6083 case EP_BlackQueen:
\r
6084 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6085 fromX = fromY = -1;
\r
6088 case EP_BlackFerz:
\r
6089 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6090 fromX = fromY = -1;
\r
6093 case EP_BlackWazir:
\r
6094 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6095 fromX = fromY = -1;
\r
6098 case EP_BlackAlfil:
\r
6099 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6100 fromX = fromY = -1;
\r
6103 case EP_BlackCannon:
\r
6104 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6105 fromX = fromY = -1;
\r
6108 case EP_BlackCardinal:
\r
6109 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6110 fromX = fromY = -1;
\r
6113 case EP_BlackMarshall:
\r
6114 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6115 fromX = fromY = -1;
\r
6118 case EP_BlackKing:
\r
6119 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6120 fromX = fromY = -1;
\r
6123 case EP_EmptySquare:
\r
6124 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6125 fromX = fromY = -1;
\r
6128 case EP_ClearBoard:
\r
6129 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6130 fromX = fromY = -1;
\r
6134 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6135 fromX = fromY = -1;
\r
6139 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6140 fromX = fromY = -1;
\r
6144 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6145 fromX = fromY = -1;
\r
6149 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6150 fromX = fromY = -1;
\r
6154 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6155 fromX = fromY = -1;
\r
6159 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6160 fromX = fromY = -1;
\r
6164 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6165 fromX = fromY = -1;
\r
6169 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6170 fromX = fromY = -1;
\r
6174 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6175 fromX = fromY = -1;
\r
6179 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6185 case CLOCK_TIMER_ID:
\r
6186 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6187 clockTimerEvent = 0;
\r
6188 DecrementClocks(); /* call into back end */
\r
6190 case LOAD_GAME_TIMER_ID:
\r
6191 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6192 loadGameTimerEvent = 0;
\r
6193 AutoPlayGameLoop(); /* call into back end */
\r
6195 case ANALYSIS_TIMER_ID:
\r
6196 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6197 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6198 AnalysisPeriodicEvent(0);
\r
6200 KillTimer(hwnd, analysisTimerEvent);
\r
6201 analysisTimerEvent = 0;
\r
6204 case DELAYED_TIMER_ID:
\r
6205 KillTimer(hwnd, delayedTimerEvent);
\r
6206 delayedTimerEvent = 0;
\r
6207 delayedTimerCallback();
\r
6212 case WM_USER_Input:
\r
6213 InputEvent(hwnd, message, wParam, lParam);
\r
6216 /* [AS] Also move "attached" child windows */
\r
6217 case WM_WINDOWPOSCHANGING:
\r
6219 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6220 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6222 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6223 /* Window is moving */
\r
6226 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6227 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6228 rcMain.right = boardX + winWidth;
\r
6229 rcMain.top = boardY;
\r
6230 rcMain.bottom = boardY + winHeight;
\r
6232 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6233 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6234 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6235 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6236 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6243 /* [AS] Snapping */
\r
6244 case WM_ENTERSIZEMOVE:
\r
6245 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6246 if (hwnd == hwndMain) {
\r
6247 doingSizing = TRUE;
\r
6250 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6254 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6255 if (hwnd == hwndMain) {
\r
6256 lastSizing = wParam;
\r
6261 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6262 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6264 case WM_EXITSIZEMOVE:
\r
6265 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6266 if (hwnd == hwndMain) {
\r
6268 doingSizing = FALSE;
\r
6269 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6270 GetClientRect(hwnd, &client);
\r
6271 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6273 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6275 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6278 case WM_DESTROY: /* message: window being destroyed */
\r
6279 PostQuitMessage(0);
\r
6283 if (hwnd == hwndMain) {
\r
6288 default: /* Passes it on if unprocessed */
\r
6289 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6294 /*---------------------------------------------------------------------------*\
\r
6296 * Misc utility routines
\r
6298 \*---------------------------------------------------------------------------*/
\r
6301 * Decent random number generator, at least not as bad as Windows
\r
6302 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6304 unsigned int randstate;
\r
6309 randstate = randstate * 1664525 + 1013904223;
\r
6310 return (int) randstate & 0x7fffffff;
\r
6314 mysrandom(unsigned int seed)
\r
6321 * returns TRUE if user selects a different color, FALSE otherwise
\r
6325 ChangeColor(HWND hwnd, COLORREF *which)
\r
6327 static BOOL firstTime = TRUE;
\r
6328 static DWORD customColors[16];
\r
6330 COLORREF newcolor;
\r
6335 /* Make initial colors in use available as custom colors */
\r
6336 /* Should we put the compiled-in defaults here instead? */
\r
6338 customColors[i++] = lightSquareColor & 0xffffff;
\r
6339 customColors[i++] = darkSquareColor & 0xffffff;
\r
6340 customColors[i++] = whitePieceColor & 0xffffff;
\r
6341 customColors[i++] = blackPieceColor & 0xffffff;
\r
6342 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6343 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6345 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6346 customColors[i++] = textAttribs[ccl].color;
\r
6348 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6349 firstTime = FALSE;
\r
6352 cc.lStructSize = sizeof(cc);
\r
6353 cc.hwndOwner = hwnd;
\r
6354 cc.hInstance = NULL;
\r
6355 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6356 cc.lpCustColors = (LPDWORD) customColors;
\r
6357 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6359 if (!ChooseColor(&cc)) return FALSE;
\r
6361 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6362 if (newcolor == *which) return FALSE;
\r
6363 *which = newcolor;
\r
6367 InitDrawingColors();
\r
6368 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6373 MyLoadSound(MySound *ms)
\r
6379 if (ms->data) free(ms->data);
\r
6382 switch (ms->name[0]) {
\r
6388 /* System sound from Control Panel. Don't preload here. */
\r
6392 if (ms->name[1] == NULLCHAR) {
\r
6393 /* "!" alone = silence */
\r
6396 /* Builtin wave resource. Error if not found. */
\r
6397 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6398 if (h == NULL) break;
\r
6399 ms->data = (void *)LoadResource(hInst, h);
\r
6400 if (h == NULL) break;
\r
6405 /* .wav file. Error if not found. */
\r
6406 f = fopen(ms->name, "rb");
\r
6407 if (f == NULL) break;
\r
6408 if (fstat(fileno(f), &st) < 0) break;
\r
6409 ms->data = malloc(st.st_size);
\r
6410 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6416 char buf[MSG_SIZ];
\r
6417 sprintf(buf, "Error loading sound %s", ms->name);
\r
6418 DisplayError(buf, GetLastError());
\r
6424 MyPlaySound(MySound *ms)
\r
6426 BOOLEAN ok = FALSE;
\r
6428 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6429 switch (ms->name[0]) {
\r
6431 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6436 /* System sound from Control Panel (deprecated feature).
\r
6437 "$" alone or an unset sound name gets default beep (still in use). */
\r
6438 if (ms->name[1]) {
\r
6439 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6441 if (!ok) ok = MessageBeep(MB_OK);
\r
6444 /* Builtin wave resource, or "!" alone for silence */
\r
6445 if (ms->name[1]) {
\r
6446 if (ms->data == NULL) return FALSE;
\r
6447 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6453 /* .wav file. Error if not found. */
\r
6454 if (ms->data == NULL) return FALSE;
\r
6455 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6458 /* Don't print an error: this can happen innocently if the sound driver
\r
6459 is busy; for instance, if another instance of WinBoard is playing
\r
6460 a sound at about the same time. */
\r
6466 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6469 OPENFILENAME *ofn;
\r
6470 static UINT *number; /* gross that this is static */
\r
6472 switch (message) {
\r
6473 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6474 /* Center the dialog over the application window */
\r
6475 ofn = (OPENFILENAME *) lParam;
\r
6476 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6477 number = (UINT *) ofn->lCustData;
\r
6478 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6482 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6483 return FALSE; /* Allow for further processing */
\r
6486 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6487 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6489 return FALSE; /* Allow for further processing */
\r
6495 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6497 static UINT *number;
\r
6498 OPENFILENAME *ofname;
\r
6501 case WM_INITDIALOG:
\r
6502 ofname = (OPENFILENAME *)lParam;
\r
6503 number = (UINT *)(ofname->lCustData);
\r
6506 ofnot = (OFNOTIFY *)lParam;
\r
6507 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6508 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6517 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6518 char *nameFilt, char *dlgTitle, UINT *number,
\r
6519 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6521 OPENFILENAME openFileName;
\r
6522 char buf1[MSG_SIZ];
\r
6525 if (fileName == NULL) fileName = buf1;
\r
6526 if (defName == NULL) {
\r
6527 strcpy(fileName, "*.");
\r
6528 strcat(fileName, defExt);
\r
6530 strcpy(fileName, defName);
\r
6532 if (fileTitle) strcpy(fileTitle, "");
\r
6533 if (number) *number = 0;
\r
6535 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6536 openFileName.hwndOwner = hwnd;
\r
6537 openFileName.hInstance = (HANDLE) hInst;
\r
6538 openFileName.lpstrFilter = nameFilt;
\r
6539 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6540 openFileName.nMaxCustFilter = 0L;
\r
6541 openFileName.nFilterIndex = 1L;
\r
6542 openFileName.lpstrFile = fileName;
\r
6543 openFileName.nMaxFile = MSG_SIZ;
\r
6544 openFileName.lpstrFileTitle = fileTitle;
\r
6545 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6546 openFileName.lpstrInitialDir = NULL;
\r
6547 openFileName.lpstrTitle = dlgTitle;
\r
6548 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6549 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6550 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6551 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6552 openFileName.nFileOffset = 0;
\r
6553 openFileName.nFileExtension = 0;
\r
6554 openFileName.lpstrDefExt = defExt;
\r
6555 openFileName.lCustData = (LONG) number;
\r
6556 openFileName.lpfnHook = oldDialog ?
\r
6557 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6558 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6560 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6561 GetOpenFileName(&openFileName)) {
\r
6562 /* open the file */
\r
6563 f = fopen(openFileName.lpstrFile, write);
\r
6565 MessageBox(hwnd, "File open failed", NULL,
\r
6566 MB_OK|MB_ICONEXCLAMATION);
\r
6570 int err = CommDlgExtendedError();
\r
6571 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6580 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6582 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6585 * Get the first pop-up menu in the menu template. This is the
\r
6586 * menu that TrackPopupMenu displays.
\r
6588 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6590 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6593 * TrackPopup uses screen coordinates, so convert the
\r
6594 * coordinates of the mouse click to screen coordinates.
\r
6596 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6598 /* Draw and track the floating pop-up menu. */
\r
6599 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6600 pt.x, pt.y, 0, hwnd, NULL);
\r
6602 /* Destroy the menu.*/
\r
6603 DestroyMenu(hmenu);
\r
6608 int sizeX, sizeY, newSizeX, newSizeY;
\r
6610 } ResizeEditPlusButtonsClosure;
\r
6613 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6615 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6619 if (hChild == cl->hText) return TRUE;
\r
6620 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6621 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6622 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6623 ScreenToClient(cl->hDlg, &pt);
\r
6624 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6625 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6629 /* Resize a dialog that has a (rich) edit field filling most of
\r
6630 the top, with a row of buttons below */
\r
6632 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6635 int newTextHeight, newTextWidth;
\r
6636 ResizeEditPlusButtonsClosure cl;
\r
6638 /*if (IsIconic(hDlg)) return;*/
\r
6639 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6641 cl.hdwp = BeginDeferWindowPos(8);
\r
6643 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6644 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6645 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6646 if (newTextHeight < 0) {
\r
6647 newSizeY += -newTextHeight;
\r
6648 newTextHeight = 0;
\r
6650 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6651 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6657 cl.newSizeX = newSizeX;
\r
6658 cl.newSizeY = newSizeY;
\r
6659 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6661 EndDeferWindowPos(cl.hdwp);
\r
6664 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6666 RECT rChild, rParent;
\r
6667 int wChild, hChild, wParent, hParent;
\r
6668 int wScreen, hScreen, xNew, yNew;
\r
6671 /* Get the Height and Width of the child window */
\r
6672 GetWindowRect (hwndChild, &rChild);
\r
6673 wChild = rChild.right - rChild.left;
\r
6674 hChild = rChild.bottom - rChild.top;
\r
6676 /* Get the Height and Width of the parent window */
\r
6677 GetWindowRect (hwndParent, &rParent);
\r
6678 wParent = rParent.right - rParent.left;
\r
6679 hParent = rParent.bottom - rParent.top;
\r
6681 /* Get the display limits */
\r
6682 hdc = GetDC (hwndChild);
\r
6683 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6684 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6685 ReleaseDC(hwndChild, hdc);
\r
6687 /* Calculate new X position, then adjust for screen */
\r
6688 xNew = rParent.left + ((wParent - wChild) /2);
\r
6691 } else if ((xNew+wChild) > wScreen) {
\r
6692 xNew = wScreen - wChild;
\r
6695 /* Calculate new Y position, then adjust for screen */
\r
6697 yNew = rParent.top + ((hParent - hChild) /2);
\r
6700 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6705 } else if ((yNew+hChild) > hScreen) {
\r
6706 yNew = hScreen - hChild;
\r
6709 /* Set it, and return */
\r
6710 return SetWindowPos (hwndChild, NULL,
\r
6711 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6714 /* Center one window over another */
\r
6715 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6717 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6720 /*---------------------------------------------------------------------------*\
\r
6722 * Startup Dialog functions
\r
6724 \*---------------------------------------------------------------------------*/
\r
6726 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6728 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6730 while (*cd != NULL) {
\r
6731 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6737 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6739 char buf1[ARG_MAX];
\r
6742 if (str[0] == '@') {
\r
6743 FILE* f = fopen(str + 1, "r");
\r
6745 DisplayFatalError(str + 1, errno, 2);
\r
6748 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6750 buf1[len] = NULLCHAR;
\r
6754 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6757 char buf[MSG_SIZ];
\r
6758 char *end = strchr(str, '\n');
\r
6759 if (end == NULL) return;
\r
6760 memcpy(buf, str, end - str);
\r
6761 buf[end - str] = NULLCHAR;
\r
6762 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6768 SetStartupDialogEnables(HWND hDlg)
\r
6770 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6771 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6772 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6773 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6774 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6775 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6776 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6777 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6778 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6779 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6780 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6781 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6782 IsDlgButtonChecked(hDlg, OPT_View));
\r
6786 QuoteForFilename(char *filename)
\r
6788 int dquote, space;
\r
6789 dquote = strchr(filename, '"') != NULL;
\r
6790 space = strchr(filename, ' ') != NULL;
\r
6791 if (dquote || space) {
\r
6803 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6805 char buf[MSG_SIZ];
\r
6808 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6809 q = QuoteForFilename(nthcp);
\r
6810 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6811 if (*nthdir != NULLCHAR) {
\r
6812 q = QuoteForFilename(nthdir);
\r
6813 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6815 if (*nthcp == NULLCHAR) {
\r
6816 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6817 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6818 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6819 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6824 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6826 char buf[MSG_SIZ];
\r
6830 switch (message) {
\r
6831 case WM_INITDIALOG:
\r
6832 /* Center the dialog */
\r
6833 CenterWindow (hDlg, GetDesktopWindow());
\r
6834 /* Initialize the dialog items */
\r
6835 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6836 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6837 firstChessProgramNames);
\r
6838 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6839 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6840 secondChessProgramNames);
\r
6841 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6842 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6843 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6844 if (*appData.icsHelper != NULLCHAR) {
\r
6845 char *q = QuoteForFilename(appData.icsHelper);
\r
6846 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6848 if (*appData.icsHost == NULLCHAR) {
\r
6849 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6850 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6851 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6852 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6853 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6856 if (appData.icsActive) {
\r
6857 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6859 else if (appData.noChessProgram) {
\r
6860 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6863 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6866 SetStartupDialogEnables(hDlg);
\r
6870 switch (LOWORD(wParam)) {
\r
6872 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6873 strcpy(buf, "/fcp=");
\r
6874 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6876 ParseArgs(StringGet, &p);
\r
6877 strcpy(buf, "/scp=");
\r
6878 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6880 ParseArgs(StringGet, &p);
\r
6881 appData.noChessProgram = FALSE;
\r
6882 appData.icsActive = FALSE;
\r
6883 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6884 strcpy(buf, "/ics /icshost=");
\r
6885 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6887 ParseArgs(StringGet, &p);
\r
6888 if (appData.zippyPlay) {
\r
6889 strcpy(buf, "/fcp=");
\r
6890 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6892 ParseArgs(StringGet, &p);
\r
6894 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6895 appData.noChessProgram = TRUE;
\r
6896 appData.icsActive = FALSE;
\r
6898 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6899 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6902 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6903 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6905 ParseArgs(StringGet, &p);
\r
6907 EndDialog(hDlg, TRUE);
\r
6914 case IDM_HELPCONTENTS:
\r
6915 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6916 MessageBox (GetFocus(),
\r
6917 "Unable to activate help",
\r
6918 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6923 SetStartupDialogEnables(hDlg);
\r
6931 /*---------------------------------------------------------------------------*\
\r
6933 * About box dialog functions
\r
6935 \*---------------------------------------------------------------------------*/
\r
6937 /* Process messages for "About" dialog box */
\r
6939 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6941 switch (message) {
\r
6942 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6943 /* Center the dialog over the application window */
\r
6944 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6945 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6949 case WM_COMMAND: /* message: received a command */
\r
6950 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6951 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6952 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6960 /*---------------------------------------------------------------------------*\
\r
6962 * Comment Dialog functions
\r
6964 \*---------------------------------------------------------------------------*/
\r
6967 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6969 static HANDLE hwndText = NULL;
\r
6970 int len, newSizeX, newSizeY, flags;
\r
6971 static int sizeX, sizeY;
\r
6976 switch (message) {
\r
6977 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6978 /* Initialize the dialog items */
\r
6979 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6980 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6981 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6982 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6983 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6984 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6985 SetWindowText(hDlg, commentTitle);
\r
6986 if (editComment) {
\r
6987 SetFocus(hwndText);
\r
6989 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6991 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6992 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6993 MAKELPARAM(FALSE, 0));
\r
6994 /* Size and position the dialog */
\r
6995 if (!commentDialog) {
\r
6996 commentDialog = hDlg;
\r
6997 flags = SWP_NOZORDER;
\r
6998 GetClientRect(hDlg, &rect);
\r
6999 sizeX = rect.right;
\r
7000 sizeY = rect.bottom;
\r
7001 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7002 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7003 WINDOWPLACEMENT wp;
\r
7004 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7005 wp.length = sizeof(WINDOWPLACEMENT);
\r
7007 wp.showCmd = SW_SHOW;
\r
7008 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7009 wp.rcNormalPosition.left = commentX;
\r
7010 wp.rcNormalPosition.right = commentX + commentW;
\r
7011 wp.rcNormalPosition.top = commentY;
\r
7012 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7013 SetWindowPlacement(hDlg, &wp);
\r
7015 GetClientRect(hDlg, &rect);
\r
7016 newSizeX = rect.right;
\r
7017 newSizeY = rect.bottom;
\r
7018 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7019 newSizeX, newSizeY);
\r
7026 case WM_COMMAND: /* message: received a command */
\r
7027 switch (LOWORD(wParam)) {
\r
7029 if (editComment) {
\r
7031 /* Read changed options from the dialog box */
\r
7032 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7033 len = GetWindowTextLength(hwndText);
\r
7034 str = (char *) malloc(len + 1);
\r
7035 GetWindowText(hwndText, str, len + 1);
\r
7044 ReplaceComment(commentIndex, str);
\r
7051 case OPT_CancelComment:
\r
7055 case OPT_ClearComment:
\r
7056 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7059 case OPT_EditComment:
\r
7060 EditCommentEvent();
\r
7069 newSizeX = LOWORD(lParam);
\r
7070 newSizeY = HIWORD(lParam);
\r
7071 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7076 case WM_GETMINMAXINFO:
\r
7077 /* Prevent resizing window too small */
\r
7078 mmi = (MINMAXINFO *) lParam;
\r
7079 mmi->ptMinTrackSize.x = 100;
\r
7080 mmi->ptMinTrackSize.y = 100;
\r
7087 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7092 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7094 if (str == NULL) str = "";
\r
7095 p = (char *) malloc(2 * strlen(str) + 2);
\r
7098 if (*str == '\n') *q++ = '\r';
\r
7102 if (commentText != NULL) free(commentText);
\r
7104 commentIndex = index;
\r
7105 commentTitle = title;
\r
7107 editComment = edit;
\r
7109 if (commentDialog) {
\r
7110 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7111 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7113 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7114 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7115 hwndMain, (DLGPROC)lpProc);
\r
7116 FreeProcInstance(lpProc);
\r
7118 commentDialogUp = TRUE;
\r
7122 /*---------------------------------------------------------------------------*\
\r
7124 * Type-in move dialog functions
\r
7126 \*---------------------------------------------------------------------------*/
\r
7129 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7131 char move[MSG_SIZ];
\r
7133 ChessMove moveType;
\r
7134 int fromX, fromY, toX, toY;
\r
7137 switch (message) {
\r
7138 case WM_INITDIALOG:
\r
7139 move[0] = (char) lParam;
\r
7140 move[1] = NULLCHAR;
\r
7141 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7142 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7143 SetWindowText(hInput, move);
\r
7145 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7149 switch (LOWORD(wParam)) {
\r
7151 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7152 { int n; Board board;
\r
7154 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7155 EditPositionPasteFEN(move);
\r
7156 EndDialog(hDlg, TRUE);
\r
7159 // [HGM] movenum: allow move number to be typed in any mode
\r
7160 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7161 currentMove = 2*n-1;
\r
7162 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7163 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7164 EndDialog(hDlg, TRUE);
\r
7165 DrawPosition(TRUE, boards[currentMove]);
\r
7166 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7167 else DisplayMessage("", "");
\r
7171 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7172 gameMode != Training) {
\r
7173 DisplayMoveError("Displayed move is not current");
\r
7175 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7176 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7177 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7178 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7179 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7180 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7181 if (gameMode != Training)
\r
7182 forwardMostMove = currentMove;
\r
7183 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7185 DisplayMoveError("Could not parse move");
\r
7188 EndDialog(hDlg, TRUE);
\r
7191 EndDialog(hDlg, FALSE);
\r
7202 PopUpMoveDialog(char firstchar)
\r
7206 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7207 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7208 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7209 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7210 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7211 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7212 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7213 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7214 gameMode == Training) {
\r
7215 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7216 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7217 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7218 FreeProcInstance(lpProc);
\r
7222 /*---------------------------------------------------------------------------*\
\r
7224 * Type-in name dialog functions
\r
7226 \*---------------------------------------------------------------------------*/
\r
7229 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7231 char move[MSG_SIZ];
\r
7234 switch (message) {
\r
7235 case WM_INITDIALOG:
\r
7236 move[0] = (char) lParam;
\r
7237 move[1] = NULLCHAR;
\r
7238 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7239 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7240 SetWindowText(hInput, move);
\r
7242 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7246 switch (LOWORD(wParam)) {
\r
7248 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7249 appData.userName = strdup(move);
\r
7252 EndDialog(hDlg, TRUE);
\r
7255 EndDialog(hDlg, FALSE);
\r
7266 PopUpNameDialog(char firstchar)
\r
7270 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7271 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7272 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7273 FreeProcInstance(lpProc);
\r
7276 /*---------------------------------------------------------------------------*\
\r
7280 \*---------------------------------------------------------------------------*/
\r
7282 /* Nonmodal error box */
\r
7283 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7284 WPARAM wParam, LPARAM lParam);
\r
7287 ErrorPopUp(char *title, char *content)
\r
7291 BOOLEAN modal = hwndMain == NULL;
\r
7309 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7310 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7313 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7315 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7316 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7317 hwndMain, (DLGPROC)lpProc);
\r
7318 FreeProcInstance(lpProc);
\r
7325 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7326 if (errorDialog == NULL) return;
\r
7327 DestroyWindow(errorDialog);
\r
7328 errorDialog = NULL;
\r
7332 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7337 switch (message) {
\r
7338 case WM_INITDIALOG:
\r
7339 GetWindowRect(hDlg, &rChild);
\r
7342 SetWindowPos(hDlg, NULL, rChild.left,
\r
7343 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7344 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7348 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7349 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7350 and it doesn't work when you resize the dialog.
\r
7351 For now, just give it a default position.
\r
7353 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7355 errorDialog = hDlg;
\r
7356 SetWindowText(hDlg, errorTitle);
\r
7357 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7358 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7362 switch (LOWORD(wParam)) {
\r
7365 if (errorDialog == hDlg) errorDialog = NULL;
\r
7366 DestroyWindow(hDlg);
\r
7378 HWND gothicDialog = NULL;
\r
7381 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7385 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7387 switch (message) {
\r
7388 case WM_INITDIALOG:
\r
7389 GetWindowRect(hDlg, &rChild);
\r
7391 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7395 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7396 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7397 and it doesn't work when you resize the dialog.
\r
7398 For now, just give it a default position.
\r
7400 gothicDialog = hDlg;
\r
7401 SetWindowText(hDlg, errorTitle);
\r
7402 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7403 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7407 switch (LOWORD(wParam)) {
\r
7410 if (errorDialog == hDlg) errorDialog = NULL;
\r
7411 DestroyWindow(hDlg);
\r
7423 GothicPopUp(char *title, VariantClass variant)
\r
7426 static char *lastTitle;
\r
7428 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7429 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7431 if(lastTitle != title && gothicDialog != NULL) {
\r
7432 DestroyWindow(gothicDialog);
\r
7433 gothicDialog = NULL;
\r
7435 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7436 title = lastTitle;
\r
7437 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7438 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7439 hwndMain, (DLGPROC)lpProc);
\r
7440 FreeProcInstance(lpProc);
\r
7445 /*---------------------------------------------------------------------------*\
\r
7447 * Ics Interaction console functions
\r
7449 \*---------------------------------------------------------------------------*/
\r
7451 #define HISTORY_SIZE 64
\r
7452 static char *history[HISTORY_SIZE];
\r
7453 int histIn = 0, histP = 0;
\r
7456 SaveInHistory(char *cmd)
\r
7458 if (history[histIn] != NULL) {
\r
7459 free(history[histIn]);
\r
7460 history[histIn] = NULL;
\r
7462 if (*cmd == NULLCHAR) return;
\r
7463 history[histIn] = StrSave(cmd);
\r
7464 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7465 if (history[histIn] != NULL) {
\r
7466 free(history[histIn]);
\r
7467 history[histIn] = NULL;
\r
7473 PrevInHistory(char *cmd)
\r
7476 if (histP == histIn) {
\r
7477 if (history[histIn] != NULL) free(history[histIn]);
\r
7478 history[histIn] = StrSave(cmd);
\r
7480 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7481 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7483 return history[histP];
\r
7489 if (histP == histIn) return NULL;
\r
7490 histP = (histP + 1) % HISTORY_SIZE;
\r
7491 return history[histP];
\r
7498 BOOLEAN immediate;
\r
7499 } IcsTextMenuEntry;
\r
7500 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7501 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7504 ParseIcsTextMenu(char *icsTextMenuString)
\r
7507 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7508 char *p = icsTextMenuString;
\r
7509 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7512 if (e->command != NULL) {
\r
7514 e->command = NULL;
\r
7518 e = icsTextMenuEntry;
\r
7519 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7520 if (*p == ';' || *p == '\n') {
\r
7521 e->item = strdup("-");
\r
7522 e->command = NULL;
\r
7524 } else if (*p == '-') {
\r
7525 e->item = strdup("-");
\r
7526 e->command = NULL;
\r
7530 char *q, *r, *s, *t;
\r
7532 q = strchr(p, ',');
\r
7533 if (q == NULL) break;
\r
7535 r = strchr(q + 1, ',');
\r
7536 if (r == NULL) break;
\r
7538 s = strchr(r + 1, ',');
\r
7539 if (s == NULL) break;
\r
7542 t = strchr(s + 1, c);
\r
7545 t = strchr(s + 1, c);
\r
7547 if (t != NULL) *t = NULLCHAR;
\r
7548 e->item = strdup(p);
\r
7549 e->command = strdup(q + 1);
\r
7550 e->getname = *(r + 1) != '0';
\r
7551 e->immediate = *(s + 1) != '0';
\r
7555 if (t == NULL) break;
\r
7564 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7568 hmenu = LoadMenu(hInst, "TextMenu");
\r
7569 h = GetSubMenu(hmenu, 0);
\r
7571 if (strcmp(e->item, "-") == 0) {
\r
7572 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7574 if (e->item[0] == '|') {
\r
7575 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7576 IDM_CommandX + i, &e->item[1]);
\r
7578 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7587 WNDPROC consoleTextWindowProc;
\r
7590 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7592 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7593 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7597 SetWindowText(hInput, command);
\r
7599 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7601 sel.cpMin = 999999;
\r
7602 sel.cpMax = 999999;
\r
7603 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7608 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7609 if (sel.cpMin == sel.cpMax) {
\r
7610 /* Expand to surrounding word */
\r
7613 tr.chrg.cpMax = sel.cpMin;
\r
7614 tr.chrg.cpMin = --sel.cpMin;
\r
7615 if (sel.cpMin < 0) break;
\r
7616 tr.lpstrText = name;
\r
7617 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7618 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7622 tr.chrg.cpMin = sel.cpMax;
\r
7623 tr.chrg.cpMax = ++sel.cpMax;
\r
7624 tr.lpstrText = name;
\r
7625 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7626 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7629 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7630 MessageBeep(MB_ICONEXCLAMATION);
\r
7634 tr.lpstrText = name;
\r
7635 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7637 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7638 MessageBeep(MB_ICONEXCLAMATION);
\r
7641 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7644 sprintf(buf, "%s %s", command, name);
\r
7645 SetWindowText(hInput, buf);
\r
7646 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7648 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7649 SetWindowText(hInput, buf);
\r
7650 sel.cpMin = 999999;
\r
7651 sel.cpMax = 999999;
\r
7652 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7658 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7663 switch (message) {
\r
7665 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7668 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7671 sel.cpMin = 999999;
\r
7672 sel.cpMax = 999999;
\r
7673 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7674 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7679 if(wParam != '\022') {
\r
7680 if (wParam == '\t') {
\r
7681 if (GetKeyState(VK_SHIFT) < 0) {
\r
7683 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7684 if (buttonDesc[0].hwnd) {
\r
7685 SetFocus(buttonDesc[0].hwnd);
\r
7687 SetFocus(hwndMain);
\r
7691 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7694 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7695 JAWS_DELETE( SetFocus(hInput); )
\r
7696 SendMessage(hInput, message, wParam, lParam);
\r
7699 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7700 case WM_RBUTTONUP:
\r
7701 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7702 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7703 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7706 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7707 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7708 if (sel.cpMin == sel.cpMax) {
\r
7709 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7710 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7712 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7713 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7715 pt.x = LOWORD(lParam);
\r
7716 pt.y = HIWORD(lParam);
\r
7717 MenuPopup(hwnd, pt, hmenu, -1);
\r
7721 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7723 return SendMessage(hInput, message, wParam, lParam);
\r
7724 case WM_MBUTTONDOWN:
\r
7725 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7726 case WM_RBUTTONDOWN:
\r
7727 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7728 /* Move selection here if it was empty */
\r
7730 pt.x = LOWORD(lParam);
\r
7731 pt.y = HIWORD(lParam);
\r
7732 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7733 if (sel.cpMin == sel.cpMax) {
\r
7734 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7735 sel.cpMax = sel.cpMin;
\r
7736 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7738 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7742 switch (LOWORD(wParam)) {
\r
7743 case IDM_QuickPaste:
\r
7745 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7746 if (sel.cpMin == sel.cpMax) {
\r
7747 MessageBeep(MB_ICONEXCLAMATION);
\r
7750 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7751 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7752 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7757 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7760 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7763 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7767 int i = LOWORD(wParam) - IDM_CommandX;
\r
7768 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7769 icsTextMenuEntry[i].command != NULL) {
\r
7770 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7771 icsTextMenuEntry[i].getname,
\r
7772 icsTextMenuEntry[i].immediate);
\r
7780 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7783 WNDPROC consoleInputWindowProc;
\r
7786 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7788 char buf[MSG_SIZ];
\r
7790 static BOOL sendNextChar = FALSE;
\r
7791 static BOOL quoteNextChar = FALSE;
\r
7792 InputSource *is = consoleInputSource;
\r
7796 switch (message) {
\r
7798 if (!appData.localLineEditing || sendNextChar) {
\r
7799 is->buf[0] = (CHAR) wParam;
\r
7801 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7802 sendNextChar = FALSE;
\r
7805 if (quoteNextChar) {
\r
7806 buf[0] = (char) wParam;
\r
7807 buf[1] = NULLCHAR;
\r
7808 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7809 quoteNextChar = FALSE;
\r
7813 case '\r': /* Enter key */
\r
7814 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7815 if (consoleEcho) SaveInHistory(is->buf);
\r
7816 is->buf[is->count++] = '\n';
\r
7817 is->buf[is->count] = NULLCHAR;
\r
7818 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7819 if (consoleEcho) {
\r
7820 ConsoleOutput(is->buf, is->count, TRUE);
\r
7821 } else if (appData.localLineEditing) {
\r
7822 ConsoleOutput("\n", 1, TRUE);
\r
7825 case '\033': /* Escape key */
\r
7826 SetWindowText(hwnd, "");
\r
7827 cf.cbSize = sizeof(CHARFORMAT);
\r
7828 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7829 if (consoleEcho) {
\r
7830 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7832 cf.crTextColor = COLOR_ECHOOFF;
\r
7834 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7835 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7837 case '\t': /* Tab key */
\r
7838 if (GetKeyState(VK_SHIFT) < 0) {
\r
7840 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7843 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7844 if (buttonDesc[0].hwnd) {
\r
7845 SetFocus(buttonDesc[0].hwnd);
\r
7847 SetFocus(hwndMain);
\r
7851 case '\023': /* Ctrl+S */
\r
7852 sendNextChar = TRUE;
\r
7854 case '\021': /* Ctrl+Q */
\r
7855 quoteNextChar = TRUE;
\r
7865 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7866 p = PrevInHistory(buf);
\r
7868 SetWindowText(hwnd, p);
\r
7869 sel.cpMin = 999999;
\r
7870 sel.cpMax = 999999;
\r
7871 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7876 p = NextInHistory();
\r
7878 SetWindowText(hwnd, p);
\r
7879 sel.cpMin = 999999;
\r
7880 sel.cpMax = 999999;
\r
7881 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7887 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7891 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7895 case WM_MBUTTONDOWN:
\r
7896 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7897 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7899 case WM_RBUTTONUP:
\r
7900 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7901 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7902 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7906 hmenu = LoadMenu(hInst, "InputMenu");
\r
7907 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7908 if (sel.cpMin == sel.cpMax) {
\r
7909 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7910 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7912 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7913 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7915 pt.x = LOWORD(lParam);
\r
7916 pt.y = HIWORD(lParam);
\r
7917 MenuPopup(hwnd, pt, hmenu, -1);
\r
7921 switch (LOWORD(wParam)) {
\r
7923 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7925 case IDM_SelectAll:
\r
7927 sel.cpMax = -1; /*999999?*/
\r
7928 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7931 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7934 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7937 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7942 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7945 #define CO_MAX 100000
\r
7946 #define CO_TRIM 1000
\r
7949 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7951 static SnapData sd;
\r
7952 HWND hText, hInput;
\r
7954 static int sizeX, sizeY;
\r
7955 int newSizeX, newSizeY;
\r
7959 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7960 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7962 switch (message) {
\r
7964 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7966 ENLINK *pLink = (ENLINK*)lParam;
\r
7967 if (pLink->msg == WM_LBUTTONUP)
\r
7971 tr.chrg = pLink->chrg;
\r
7972 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7973 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7974 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7975 free(tr.lpstrText);
\r
7979 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7980 hwndConsole = hDlg;
\r
7982 consoleTextWindowProc = (WNDPROC)
\r
7983 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7984 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7985 consoleInputWindowProc = (WNDPROC)
\r
7986 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7987 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7988 Colorize(ColorNormal, TRUE);
\r
7989 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7990 ChangedConsoleFont();
\r
7991 GetClientRect(hDlg, &rect);
\r
7992 sizeX = rect.right;
\r
7993 sizeY = rect.bottom;
\r
7994 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7995 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7996 WINDOWPLACEMENT wp;
\r
7997 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7998 wp.length = sizeof(WINDOWPLACEMENT);
\r
8000 wp.showCmd = SW_SHOW;
\r
8001 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8002 wp.rcNormalPosition.left = wpConsole.x;
\r
8003 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8004 wp.rcNormalPosition.top = wpConsole.y;
\r
8005 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8006 SetWindowPlacement(hDlg, &wp);
\r
8009 // [HGM] Chessknight's change 2004-07-13
\r
8010 else { /* Determine Defaults */
\r
8011 WINDOWPLACEMENT wp;
\r
8012 wpConsole.x = winWidth + 1;
\r
8013 wpConsole.y = boardY;
\r
8014 wpConsole.width = screenWidth - winWidth;
\r
8015 wpConsole.height = winHeight;
\r
8016 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8017 wp.length = sizeof(WINDOWPLACEMENT);
\r
8019 wp.showCmd = SW_SHOW;
\r
8020 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8021 wp.rcNormalPosition.left = wpConsole.x;
\r
8022 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8023 wp.rcNormalPosition.top = wpConsole.y;
\r
8024 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8025 SetWindowPlacement(hDlg, &wp);
\r
8028 // Allow hText to highlight URLs and send notifications on them
\r
8029 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8030 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8031 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8032 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8046 if (IsIconic(hDlg)) break;
\r
8047 newSizeX = LOWORD(lParam);
\r
8048 newSizeY = HIWORD(lParam);
\r
8049 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8050 RECT rectText, rectInput;
\r
8052 int newTextHeight, newTextWidth;
\r
8053 GetWindowRect(hText, &rectText);
\r
8054 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8055 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8056 if (newTextHeight < 0) {
\r
8057 newSizeY += -newTextHeight;
\r
8058 newTextHeight = 0;
\r
8060 SetWindowPos(hText, NULL, 0, 0,
\r
8061 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8062 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8063 pt.x = rectInput.left;
\r
8064 pt.y = rectInput.top + newSizeY - sizeY;
\r
8065 ScreenToClient(hDlg, &pt);
\r
8066 SetWindowPos(hInput, NULL,
\r
8067 pt.x, pt.y, /* needs client coords */
\r
8068 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8069 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8075 case WM_GETMINMAXINFO:
\r
8076 /* Prevent resizing window too small */
\r
8077 mmi = (MINMAXINFO *) lParam;
\r
8078 mmi->ptMinTrackSize.x = 100;
\r
8079 mmi->ptMinTrackSize.y = 100;
\r
8082 /* [AS] Snapping */
\r
8083 case WM_ENTERSIZEMOVE:
\r
8084 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8087 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8090 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8092 case WM_EXITSIZEMOVE:
\r
8093 UpdateICSWidth(hText);
\r
8094 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8097 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8105 if (hwndConsole) return;
\r
8106 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8107 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8112 ConsoleOutput(char* data, int length, int forceVisible)
\r
8117 char buf[CO_MAX+1];
\r
8120 static int delayLF = 0;
\r
8121 CHARRANGE savesel, sel;
\r
8123 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8131 while (length--) {
\r
8139 } else if (*p == '\007') {
\r
8140 MyPlaySound(&sounds[(int)SoundBell]);
\r
8147 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8148 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8149 /* Save current selection */
\r
8150 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8151 exlen = GetWindowTextLength(hText);
\r
8152 /* Find out whether current end of text is visible */
\r
8153 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8154 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8155 /* Trim existing text if it's too long */
\r
8156 if (exlen + (q - buf) > CO_MAX) {
\r
8157 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8160 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8161 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8163 savesel.cpMin -= trim;
\r
8164 savesel.cpMax -= trim;
\r
8165 if (exlen < 0) exlen = 0;
\r
8166 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8167 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8169 /* Append the new text */
\r
8170 sel.cpMin = exlen;
\r
8171 sel.cpMax = exlen;
\r
8172 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8173 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8174 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8175 if (forceVisible || exlen == 0 ||
\r
8176 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8177 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8178 /* Scroll to make new end of text visible if old end of text
\r
8179 was visible or new text is an echo of user typein */
\r
8180 sel.cpMin = 9999999;
\r
8181 sel.cpMax = 9999999;
\r
8182 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8183 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8184 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8185 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8187 if (savesel.cpMax == exlen || forceVisible) {
\r
8188 /* Move insert point to new end of text if it was at the old
\r
8189 end of text or if the new text is an echo of user typein */
\r
8190 sel.cpMin = 9999999;
\r
8191 sel.cpMax = 9999999;
\r
8192 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8194 /* Restore previous selection */
\r
8195 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8197 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8204 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8208 COLORREF oldFg, oldBg;
\r
8212 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8214 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8215 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8216 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8219 rect.right = x + squareSize;
\r
8221 rect.bottom = y + squareSize;
\r
8224 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8225 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8226 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8227 &rect, str, strlen(str), NULL);
\r
8229 (void) SetTextColor(hdc, oldFg);
\r
8230 (void) SetBkColor(hdc, oldBg);
\r
8231 (void) SelectObject(hdc, oldFont);
\r
8235 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8236 RECT *rect, char *color, char *flagFell)
\r
8240 COLORREF oldFg, oldBg;
\r
8243 if (appData.clockMode) {
\r
8245 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8247 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8254 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8255 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8257 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8258 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8260 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8264 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8265 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8266 rect, str, strlen(str), NULL);
\r
8267 if(logoHeight > 0 && appData.clockMode) {
\r
8269 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8270 r.top = rect->top + logoHeight/2;
\r
8271 r.left = rect->left;
\r
8272 r.right = rect->right;
\r
8273 r.bottom = rect->bottom;
\r
8274 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8275 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8276 &r, str, strlen(str), NULL);
\r
8278 (void) SetTextColor(hdc, oldFg);
\r
8279 (void) SetBkColor(hdc, oldBg);
\r
8280 (void) SelectObject(hdc, oldFont);
\r
8285 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8291 if( count <= 0 ) {
\r
8292 if (appData.debugMode) {
\r
8293 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8296 return ERROR_INVALID_USER_BUFFER;
\r
8299 ResetEvent(ovl->hEvent);
\r
8300 ovl->Offset = ovl->OffsetHigh = 0;
\r
8301 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8305 err = GetLastError();
\r
8306 if (err == ERROR_IO_PENDING) {
\r
8307 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8311 err = GetLastError();
\r
8318 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8323 ResetEvent(ovl->hEvent);
\r
8324 ovl->Offset = ovl->OffsetHigh = 0;
\r
8325 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8329 err = GetLastError();
\r
8330 if (err == ERROR_IO_PENDING) {
\r
8331 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8335 err = GetLastError();
\r
8341 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8342 void CheckForInputBufferFull( InputSource * is )
\r
8344 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8345 /* Look for end of line */
\r
8346 char * p = is->buf;
\r
8348 while( p < is->next && *p != '\n' ) {
\r
8352 if( p >= is->next ) {
\r
8353 if (appData.debugMode) {
\r
8354 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8357 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8358 is->count = (DWORD) -1;
\r
8359 is->next = is->buf;
\r
8365 InputThread(LPVOID arg)
\r
8370 is = (InputSource *) arg;
\r
8371 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8372 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8373 while (is->hThread != NULL) {
\r
8374 is->error = DoReadFile(is->hFile, is->next,
\r
8375 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8376 &is->count, &ovl);
\r
8377 if (is->error == NO_ERROR) {
\r
8378 is->next += is->count;
\r
8380 if (is->error == ERROR_BROKEN_PIPE) {
\r
8381 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8384 is->count = (DWORD) -1;
\r
8385 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8390 CheckForInputBufferFull( is );
\r
8392 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8394 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8396 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8399 CloseHandle(ovl.hEvent);
\r
8400 CloseHandle(is->hFile);
\r
8402 if (appData.debugMode) {
\r
8403 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8410 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8412 NonOvlInputThread(LPVOID arg)
\r
8419 is = (InputSource *) arg;
\r
8420 while (is->hThread != NULL) {
\r
8421 is->error = ReadFile(is->hFile, is->next,
\r
8422 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8423 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8424 if (is->error == NO_ERROR) {
\r
8425 /* Change CRLF to LF */
\r
8426 if (is->next > is->buf) {
\r
8428 i = is->count + 1;
\r
8436 if (prev == '\r' && *p == '\n') {
\r
8448 if (is->error == ERROR_BROKEN_PIPE) {
\r
8449 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8452 is->count = (DWORD) -1;
\r
8456 CheckForInputBufferFull( is );
\r
8458 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8460 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8462 if (is->count < 0) break; /* Quit on error */
\r
8464 CloseHandle(is->hFile);
\r
8469 SocketInputThread(LPVOID arg)
\r
8473 is = (InputSource *) arg;
\r
8474 while (is->hThread != NULL) {
\r
8475 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8476 if ((int)is->count == SOCKET_ERROR) {
\r
8477 is->count = (DWORD) -1;
\r
8478 is->error = WSAGetLastError();
\r
8480 is->error = NO_ERROR;
\r
8481 is->next += is->count;
\r
8482 if (is->count == 0 && is->second == is) {
\r
8483 /* End of file on stderr; quit with no message */
\r
8487 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8489 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8491 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8497 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8501 is = (InputSource *) lParam;
\r
8502 if (is->lineByLine) {
\r
8503 /* Feed in lines one by one */
\r
8504 char *p = is->buf;
\r
8506 while (q < is->next) {
\r
8507 if (*q++ == '\n') {
\r
8508 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8513 /* Move any partial line to the start of the buffer */
\r
8515 while (p < is->next) {
\r
8520 if (is->error != NO_ERROR || is->count == 0) {
\r
8521 /* Notify backend of the error. Note: If there was a partial
\r
8522 line at the end, it is not flushed through. */
\r
8523 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8526 /* Feed in the whole chunk of input at once */
\r
8527 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8528 is->next = is->buf;
\r
8532 /*---------------------------------------------------------------------------*\
\r
8534 * Menu enables. Used when setting various modes.
\r
8536 \*---------------------------------------------------------------------------*/
\r
8544 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8546 while (enab->item > 0) {
\r
8547 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8552 Enables gnuEnables[] = {
\r
8553 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8567 Enables icsEnables[] = {
\r
8568 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8575 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8580 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8581 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8587 Enables zippyEnables[] = {
\r
8588 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8589 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8590 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8591 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8596 Enables ncpEnables[] = {
\r
8597 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8606 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8619 Enables trainingOnEnables[] = {
\r
8620 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8621 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8622 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8623 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8624 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8625 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8626 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8627 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8631 Enables trainingOffEnables[] = {
\r
8632 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8635 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8636 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8637 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8643 /* These modify either ncpEnables or gnuEnables */
\r
8644 Enables cmailEnables[] = {
\r
8645 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8646 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8647 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8648 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8650 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8655 Enables machineThinkingEnables[] = {
\r
8656 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8663 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8664 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8665 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8666 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8667 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8668 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8669 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8670 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8674 Enables userThinkingEnables[] = {
\r
8675 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8676 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8677 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8678 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8679 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8680 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8681 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8682 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8683 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8684 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8685 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8686 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8687 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8688 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8689 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8693 /*---------------------------------------------------------------------------*\
\r
8695 * Front-end interface functions exported by XBoard.
\r
8696 * Functions appear in same order as prototypes in frontend.h.
\r
8698 \*---------------------------------------------------------------------------*/
\r
8702 static UINT prevChecked = 0;
\r
8703 static int prevPausing = 0;
\r
8706 if (pausing != prevPausing) {
\r
8707 prevPausing = pausing;
\r
8708 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8709 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8710 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8713 switch (gameMode) {
\r
8714 case BeginningOfGame:
\r
8715 if (appData.icsActive)
\r
8716 nowChecked = IDM_IcsClient;
\r
8717 else if (appData.noChessProgram)
\r
8718 nowChecked = IDM_EditGame;
\r
8720 nowChecked = IDM_MachineBlack;
\r
8722 case MachinePlaysBlack:
\r
8723 nowChecked = IDM_MachineBlack;
\r
8725 case MachinePlaysWhite:
\r
8726 nowChecked = IDM_MachineWhite;
\r
8728 case TwoMachinesPlay:
\r
8729 nowChecked = IDM_TwoMachines;
\r
8732 nowChecked = IDM_AnalysisMode;
\r
8735 nowChecked = IDM_AnalyzeFile;
\r
8738 nowChecked = IDM_EditGame;
\r
8740 case PlayFromGameFile:
\r
8741 nowChecked = IDM_LoadGame;
\r
8743 case EditPosition:
\r
8744 nowChecked = IDM_EditPosition;
\r
8747 nowChecked = IDM_Training;
\r
8749 case IcsPlayingWhite:
\r
8750 case IcsPlayingBlack:
\r
8751 case IcsObserving:
\r
8753 nowChecked = IDM_IcsClient;
\r
8760 if (prevChecked != 0)
\r
8761 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8762 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8763 if (nowChecked != 0)
\r
8764 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8765 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8767 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8768 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8769 MF_BYCOMMAND|MF_ENABLED);
\r
8771 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8772 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8775 prevChecked = nowChecked;
\r
8777 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8778 if (appData.icsActive) {
\r
8779 if (appData.icsEngineAnalyze) {
\r
8780 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8781 MF_BYCOMMAND|MF_CHECKED);
\r
8783 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8784 MF_BYCOMMAND|MF_UNCHECKED);
\r
8792 HMENU hmenu = GetMenu(hwndMain);
\r
8793 SetMenuEnables(hmenu, icsEnables);
\r
8794 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8795 MF_BYPOSITION|MF_ENABLED);
\r
8797 if (appData.zippyPlay) {
\r
8798 SetMenuEnables(hmenu, zippyEnables);
\r
8799 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8800 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8801 MF_BYCOMMAND|MF_ENABLED);
\r
8809 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8815 HMENU hmenu = GetMenu(hwndMain);
\r
8816 SetMenuEnables(hmenu, ncpEnables);
\r
8817 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8818 MF_BYPOSITION|MF_GRAYED);
\r
8819 DrawMenuBar(hwndMain);
\r
8825 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8829 SetTrainingModeOn()
\r
8832 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8833 for (i = 0; i < N_BUTTONS; i++) {
\r
8834 if (buttonDesc[i].hwnd != NULL)
\r
8835 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8840 VOID SetTrainingModeOff()
\r
8843 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8844 for (i = 0; i < N_BUTTONS; i++) {
\r
8845 if (buttonDesc[i].hwnd != NULL)
\r
8846 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8852 SetUserThinkingEnables()
\r
8854 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8858 SetMachineThinkingEnables()
\r
8860 HMENU hMenu = GetMenu(hwndMain);
\r
8861 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8863 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8865 if (gameMode == MachinePlaysBlack) {
\r
8866 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8867 } else if (gameMode == MachinePlaysWhite) {
\r
8868 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8869 } else if (gameMode == TwoMachinesPlay) {
\r
8870 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8876 DisplayTitle(char *str)
\r
8878 char title[MSG_SIZ], *host;
\r
8879 if (str[0] != NULLCHAR) {
\r
8880 strcpy(title, str);
\r
8881 } else if (appData.icsActive) {
\r
8882 if (appData.icsCommPort[0] != NULLCHAR)
\r
8885 host = appData.icsHost;
\r
8886 sprintf(title, "%s: %s", szTitle, host);
\r
8887 } else if (appData.noChessProgram) {
\r
8888 strcpy(title, szTitle);
\r
8890 strcpy(title, szTitle);
\r
8891 strcat(title, ": ");
\r
8892 strcat(title, first.tidy);
\r
8894 SetWindowText(hwndMain, title);
\r
8899 DisplayMessage(char *str1, char *str2)
\r
8903 int remain = MESSAGE_TEXT_MAX - 1;
\r
8906 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8907 messageText[0] = NULLCHAR;
\r
8909 len = strlen(str1);
\r
8910 if (len > remain) len = remain;
\r
8911 strncpy(messageText, str1, len);
\r
8912 messageText[len] = NULLCHAR;
\r
8915 if (*str2 && remain >= 2) {
\r
8917 strcat(messageText, " ");
\r
8920 len = strlen(str2);
\r
8921 if (len > remain) len = remain;
\r
8922 strncat(messageText, str2, len);
\r
8924 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8926 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8930 hdc = GetDC(hwndMain);
\r
8931 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8932 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8933 &messageRect, messageText, strlen(messageText), NULL);
\r
8934 (void) SelectObject(hdc, oldFont);
\r
8935 (void) ReleaseDC(hwndMain, hdc);
\r
8939 DisplayError(char *str, int error)
\r
8941 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8947 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8948 NULL, error, LANG_NEUTRAL,
\r
8949 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8951 sprintf(buf, "%s:\n%s", str, buf2);
\r
8953 ErrorMap *em = errmap;
\r
8954 while (em->err != 0 && em->err != error) em++;
\r
8955 if (em->err != 0) {
\r
8956 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8958 sprintf(buf, "%s:\nError code %d", str, error);
\r
8963 ErrorPopUp("Error", buf);
\r
8968 DisplayMoveError(char *str)
\r
8970 fromX = fromY = -1;
\r
8971 ClearHighlights();
\r
8972 DrawPosition(FALSE, NULL);
\r
8973 if (appData.popupMoveErrors) {
\r
8974 ErrorPopUp("Error", str);
\r
8976 DisplayMessage(str, "");
\r
8977 moveErrorMessageUp = TRUE;
\r
8982 DisplayFatalError(char *str, int error, int exitStatus)
\r
8984 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8986 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8989 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8990 NULL, error, LANG_NEUTRAL,
\r
8991 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8993 sprintf(buf, "%s:\n%s", str, buf2);
\r
8995 ErrorMap *em = errmap;
\r
8996 while (em->err != 0 && em->err != error) em++;
\r
8997 if (em->err != 0) {
\r
8998 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9000 sprintf(buf, "%s:\nError code %d", str, error);
\r
9005 if (appData.debugMode) {
\r
9006 fprintf(debugFP, "%s: %s\n", label, str);
\r
9008 if (appData.popupExitMessage) {
\r
9009 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9010 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9012 ExitEvent(exitStatus);
\r
9017 DisplayInformation(char *str)
\r
9019 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9024 DisplayNote(char *str)
\r
9026 ErrorPopUp("Note", str);
\r
9031 char *title, *question, *replyPrefix;
\r
9036 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9038 static QuestionParams *qp;
\r
9039 char reply[MSG_SIZ];
\r
9042 switch (message) {
\r
9043 case WM_INITDIALOG:
\r
9044 qp = (QuestionParams *) lParam;
\r
9045 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9046 SetWindowText(hDlg, qp->title);
\r
9047 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9048 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9052 switch (LOWORD(wParam)) {
\r
9054 strcpy(reply, qp->replyPrefix);
\r
9055 if (*reply) strcat(reply, " ");
\r
9056 len = strlen(reply);
\r
9057 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9058 strcat(reply, "\n");
\r
9059 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9060 EndDialog(hDlg, TRUE);
\r
9061 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9064 EndDialog(hDlg, FALSE);
\r
9075 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9077 QuestionParams qp;
\r
9081 qp.question = question;
\r
9082 qp.replyPrefix = replyPrefix;
\r
9084 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9085 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9086 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9087 FreeProcInstance(lpProc);
\r
9090 /* [AS] Pick FRC position */
\r
9091 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9093 static int * lpIndexFRC;
\r
9099 case WM_INITDIALOG:
\r
9100 lpIndexFRC = (int *) lParam;
\r
9102 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9104 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9105 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9106 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9107 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9112 switch( LOWORD(wParam) ) {
\r
9114 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9115 EndDialog( hDlg, 0 );
\r
9116 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9119 EndDialog( hDlg, 1 );
\r
9121 case IDC_NFG_Edit:
\r
9122 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9123 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9125 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9128 case IDC_NFG_Random:
\r
9129 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9130 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9143 int index = appData.defaultFrcPosition;
\r
9144 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9146 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9148 if( result == 0 ) {
\r
9149 appData.defaultFrcPosition = index;
\r
9155 /* [AS] Game list options */
\r
9161 static GLT_Item GLT_ItemInfo[] = {
\r
9162 { GLT_EVENT, "Event" },
\r
9163 { GLT_SITE, "Site" },
\r
9164 { GLT_DATE, "Date" },
\r
9165 { GLT_ROUND, "Round" },
\r
9166 { GLT_PLAYERS, "Players" },
\r
9167 { GLT_RESULT, "Result" },
\r
9168 { GLT_WHITE_ELO, "White Rating" },
\r
9169 { GLT_BLACK_ELO, "Black Rating" },
\r
9170 { GLT_TIME_CONTROL,"Time Control" },
\r
9171 { GLT_VARIANT, "Variant" },
\r
9172 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9173 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9177 const char * GLT_FindItem( char id )
\r
9179 const char * result = 0;
\r
9181 GLT_Item * list = GLT_ItemInfo;
\r
9183 while( list->id != 0 ) {
\r
9184 if( list->id == id ) {
\r
9185 result = list->name;
\r
9195 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9197 const char * name = GLT_FindItem( id );
\r
9200 if( index >= 0 ) {
\r
9201 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9204 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9209 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9213 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9216 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9220 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9222 pc = GLT_ALL_TAGS;
\r
9225 if( strchr( tags, *pc ) == 0 ) {
\r
9226 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9231 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9234 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9236 char result = '\0';
\r
9239 GLT_Item * list = GLT_ItemInfo;
\r
9241 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9242 while( list->id != 0 ) {
\r
9243 if( strcmp( list->name, name ) == 0 ) {
\r
9244 result = list->id;
\r
9255 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9257 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9258 int idx2 = idx1 + delta;
\r
9259 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9261 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9264 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9265 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9266 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9267 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9271 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9273 static char glt[64];
\r
9274 static char * lpUserGLT;
\r
9278 case WM_INITDIALOG:
\r
9279 lpUserGLT = (char *) lParam;
\r
9281 strcpy( glt, lpUserGLT );
\r
9283 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9285 /* Initialize list */
\r
9286 GLT_TagsToList( hDlg, glt );
\r
9288 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9293 switch( LOWORD(wParam) ) {
\r
9296 char * pc = lpUserGLT;
\r
9298 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9302 id = GLT_ListItemToTag( hDlg, idx );
\r
9306 } while( id != '\0' );
\r
9308 EndDialog( hDlg, 0 );
\r
9311 EndDialog( hDlg, 1 );
\r
9314 case IDC_GLT_Default:
\r
9315 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9316 GLT_TagsToList( hDlg, glt );
\r
9319 case IDC_GLT_Restore:
\r
9320 strcpy( glt, lpUserGLT );
\r
9321 GLT_TagsToList( hDlg, glt );
\r
9325 GLT_MoveSelection( hDlg, -1 );
\r
9328 case IDC_GLT_Down:
\r
9329 GLT_MoveSelection( hDlg, +1 );
\r
9339 int GameListOptions()
\r
9343 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9345 strcpy( glt, appData.gameListTags );
\r
9347 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9349 if( result == 0 ) {
\r
9350 /* [AS] Memory leak here! */
\r
9351 appData.gameListTags = strdup( glt );
\r
9359 DisplayIcsInteractionTitle(char *str)
\r
9361 char consoleTitle[MSG_SIZ];
\r
9363 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9364 SetWindowText(hwndConsole, consoleTitle);
\r
9368 DrawPosition(int fullRedraw, Board board)
\r
9370 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9373 void NotifyFrontendLogin()
\r
9376 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9382 fromX = fromY = -1;
\r
9383 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9384 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9385 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9386 dragInfo.lastpos = dragInfo.pos;
\r
9387 dragInfo.start.x = dragInfo.start.y = -1;
\r
9388 dragInfo.from = dragInfo.start;
\r
9390 DrawPosition(TRUE, NULL);
\r
9396 CommentPopUp(char *title, char *str)
\r
9398 HWND hwnd = GetActiveWindow();
\r
9399 EitherCommentPopUp(0, title, str, FALSE);
\r
9401 SetActiveWindow(hwnd);
\r
9405 CommentPopDown(void)
\r
9407 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9408 if (commentDialog) {
\r
9409 ShowWindow(commentDialog, SW_HIDE);
\r
9411 commentDialogUp = FALSE;
\r
9415 EditCommentPopUp(int index, char *title, char *str)
\r
9417 EitherCommentPopUp(index, title, str, TRUE);
\r
9424 MyPlaySound(&sounds[(int)SoundMove]);
\r
9427 VOID PlayIcsWinSound()
\r
9429 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9432 VOID PlayIcsLossSound()
\r
9434 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9437 VOID PlayIcsDrawSound()
\r
9439 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9442 VOID PlayIcsUnfinishedSound()
\r
9444 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9450 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9458 consoleEcho = TRUE;
\r
9459 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9460 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9461 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9470 consoleEcho = FALSE;
\r
9471 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9472 /* This works OK: set text and background both to the same color */
\r
9474 cf.crTextColor = COLOR_ECHOOFF;
\r
9475 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9476 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9479 /* No Raw()...? */
\r
9481 void Colorize(ColorClass cc, int continuation)
\r
9483 currentColorClass = cc;
\r
9484 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9485 consoleCF.crTextColor = textAttribs[cc].color;
\r
9486 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9487 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9493 static char buf[MSG_SIZ];
\r
9494 DWORD bufsiz = MSG_SIZ;
\r
9496 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9497 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9499 if (!GetUserName(buf, &bufsiz)) {
\r
9500 /*DisplayError("Error getting user name", GetLastError());*/
\r
9501 strcpy(buf, "User");
\r
9509 static char buf[MSG_SIZ];
\r
9510 DWORD bufsiz = MSG_SIZ;
\r
9512 if (!GetComputerName(buf, &bufsiz)) {
\r
9513 /*DisplayError("Error getting host name", GetLastError());*/
\r
9514 strcpy(buf, "Unknown");
\r
9521 ClockTimerRunning()
\r
9523 return clockTimerEvent != 0;
\r
9529 if (clockTimerEvent == 0) return FALSE;
\r
9530 KillTimer(hwndMain, clockTimerEvent);
\r
9531 clockTimerEvent = 0;
\r
9536 StartClockTimer(long millisec)
\r
9538 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9539 (UINT) millisec, NULL);
\r
9543 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9546 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9548 if(appData.noGUI) return;
\r
9549 hdc = GetDC(hwndMain);
\r
9550 if (!IsIconic(hwndMain)) {
\r
9551 DisplayAClock(hdc, timeRemaining, highlight,
\r
9552 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9554 if (highlight && iconCurrent == iconBlack) {
\r
9555 iconCurrent = iconWhite;
\r
9556 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9557 if (IsIconic(hwndMain)) {
\r
9558 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9561 (void) ReleaseDC(hwndMain, hdc);
\r
9563 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9567 DisplayBlackClock(long timeRemaining, int highlight)
\r
9570 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9572 if(appData.noGUI) return;
\r
9573 hdc = GetDC(hwndMain);
\r
9574 if (!IsIconic(hwndMain)) {
\r
9575 DisplayAClock(hdc, timeRemaining, highlight,
\r
9576 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9578 if (highlight && iconCurrent == iconWhite) {
\r
9579 iconCurrent = iconBlack;
\r
9580 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9581 if (IsIconic(hwndMain)) {
\r
9582 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9585 (void) ReleaseDC(hwndMain, hdc);
\r
9587 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9592 LoadGameTimerRunning()
\r
9594 return loadGameTimerEvent != 0;
\r
9598 StopLoadGameTimer()
\r
9600 if (loadGameTimerEvent == 0) return FALSE;
\r
9601 KillTimer(hwndMain, loadGameTimerEvent);
\r
9602 loadGameTimerEvent = 0;
\r
9607 StartLoadGameTimer(long millisec)
\r
9609 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9610 (UINT) millisec, NULL);
\r
9618 char fileTitle[MSG_SIZ];
\r
9620 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9621 f = OpenFileDialog(hwndMain, "a", defName,
\r
9622 appData.oldSaveStyle ? "gam" : "pgn",
\r
9624 "Save Game to File", NULL, fileTitle, NULL);
\r
9626 SaveGame(f, 0, "");
\r
9633 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9635 if (delayedTimerEvent != 0) {
\r
9636 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9637 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9639 KillTimer(hwndMain, delayedTimerEvent);
\r
9640 delayedTimerEvent = 0;
\r
9641 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9642 delayedTimerCallback();
\r
9644 delayedTimerCallback = cb;
\r
9645 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9646 (UINT) millisec, NULL);
\r
9649 DelayedEventCallback
\r
9652 if (delayedTimerEvent) {
\r
9653 return delayedTimerCallback;
\r
9660 CancelDelayedEvent()
\r
9662 if (delayedTimerEvent) {
\r
9663 KillTimer(hwndMain, delayedTimerEvent);
\r
9664 delayedTimerEvent = 0;
\r
9668 DWORD GetWin32Priority(int nice)
\r
9669 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9671 REALTIME_PRIORITY_CLASS 0x00000100
\r
9672 HIGH_PRIORITY_CLASS 0x00000080
\r
9673 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9674 NORMAL_PRIORITY_CLASS 0x00000020
\r
9675 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9676 IDLE_PRIORITY_CLASS 0x00000040
\r
9678 if (nice < -15) return 0x00000080;
\r
9679 if (nice < 0) return 0x00008000;
\r
9680 if (nice == 0) return 0x00000020;
\r
9681 if (nice < 15) return 0x00004000;
\r
9682 return 0x00000040;
\r
9685 /* Start a child process running the given program.
\r
9686 The process's standard output can be read from "from", and its
\r
9687 standard input can be written to "to".
\r
9688 Exit with fatal error if anything goes wrong.
\r
9689 Returns an opaque pointer that can be used to destroy the process
\r
9693 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9695 #define BUFSIZE 4096
\r
9697 HANDLE hChildStdinRd, hChildStdinWr,
\r
9698 hChildStdoutRd, hChildStdoutWr;
\r
9699 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9700 SECURITY_ATTRIBUTES saAttr;
\r
9702 PROCESS_INFORMATION piProcInfo;
\r
9703 STARTUPINFO siStartInfo;
\r
9705 char buf[MSG_SIZ];
\r
9708 if (appData.debugMode) {
\r
9709 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9714 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9715 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9716 saAttr.bInheritHandle = TRUE;
\r
9717 saAttr.lpSecurityDescriptor = NULL;
\r
9720 * The steps for redirecting child's STDOUT:
\r
9721 * 1. Create anonymous pipe to be STDOUT for child.
\r
9722 * 2. Create a noninheritable duplicate of read handle,
\r
9723 * and close the inheritable read handle.
\r
9726 /* Create a pipe for the child's STDOUT. */
\r
9727 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9728 return GetLastError();
\r
9731 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9732 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9733 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9734 FALSE, /* not inherited */
\r
9735 DUPLICATE_SAME_ACCESS);
\r
9737 return GetLastError();
\r
9739 CloseHandle(hChildStdoutRd);
\r
9742 * The steps for redirecting child's STDIN:
\r
9743 * 1. Create anonymous pipe to be STDIN for child.
\r
9744 * 2. Create a noninheritable duplicate of write handle,
\r
9745 * and close the inheritable write handle.
\r
9748 /* Create a pipe for the child's STDIN. */
\r
9749 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9750 return GetLastError();
\r
9753 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9754 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9755 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9756 FALSE, /* not inherited */
\r
9757 DUPLICATE_SAME_ACCESS);
\r
9759 return GetLastError();
\r
9761 CloseHandle(hChildStdinWr);
\r
9763 /* Arrange to (1) look in dir for the child .exe file, and
\r
9764 * (2) have dir be the child's working directory. Interpret
\r
9765 * dir relative to the directory WinBoard loaded from. */
\r
9766 GetCurrentDirectory(MSG_SIZ, buf);
\r
9767 SetCurrentDirectory(installDir);
\r
9768 SetCurrentDirectory(dir);
\r
9770 /* Now create the child process. */
\r
9772 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9773 siStartInfo.lpReserved = NULL;
\r
9774 siStartInfo.lpDesktop = NULL;
\r
9775 siStartInfo.lpTitle = NULL;
\r
9776 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9777 siStartInfo.cbReserved2 = 0;
\r
9778 siStartInfo.lpReserved2 = NULL;
\r
9779 siStartInfo.hStdInput = hChildStdinRd;
\r
9780 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9781 siStartInfo.hStdError = hChildStdoutWr;
\r
9783 fSuccess = CreateProcess(NULL,
\r
9784 cmdLine, /* command line */
\r
9785 NULL, /* process security attributes */
\r
9786 NULL, /* primary thread security attrs */
\r
9787 TRUE, /* handles are inherited */
\r
9788 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9789 NULL, /* use parent's environment */
\r
9791 &siStartInfo, /* STARTUPINFO pointer */
\r
9792 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9794 err = GetLastError();
\r
9795 SetCurrentDirectory(buf); /* return to prev directory */
\r
9800 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9801 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9802 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9805 /* Close the handles we don't need in the parent */
\r
9806 CloseHandle(piProcInfo.hThread);
\r
9807 CloseHandle(hChildStdinRd);
\r
9808 CloseHandle(hChildStdoutWr);
\r
9810 /* Prepare return value */
\r
9811 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9812 cp->kind = CPReal;
\r
9813 cp->hProcess = piProcInfo.hProcess;
\r
9814 cp->pid = piProcInfo.dwProcessId;
\r
9815 cp->hFrom = hChildStdoutRdDup;
\r
9816 cp->hTo = hChildStdinWrDup;
\r
9818 *pr = (void *) cp;
\r
9820 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9821 2000 where engines sometimes don't see the initial command(s)
\r
9822 from WinBoard and hang. I don't understand how that can happen,
\r
9823 but the Sleep is harmless, so I've put it in. Others have also
\r
9824 reported what may be the same problem, so hopefully this will fix
\r
9825 it for them too. */
\r
9833 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9835 ChildProc *cp; int result;
\r
9837 cp = (ChildProc *) pr;
\r
9838 if (cp == NULL) return;
\r
9840 switch (cp->kind) {
\r
9842 /* TerminateProcess is considered harmful, so... */
\r
9843 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9844 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9845 /* The following doesn't work because the chess program
\r
9846 doesn't "have the same console" as WinBoard. Maybe
\r
9847 we could arrange for this even though neither WinBoard
\r
9848 nor the chess program uses a console for stdio? */
\r
9849 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9851 /* [AS] Special termination modes for misbehaving programs... */
\r
9852 if( signal == 9 ) {
\r
9853 result = TerminateProcess( cp->hProcess, 0 );
\r
9855 if ( appData.debugMode) {
\r
9856 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9859 else if( signal == 10 ) {
\r
9860 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9862 if( dw != WAIT_OBJECT_0 ) {
\r
9863 result = TerminateProcess( cp->hProcess, 0 );
\r
9865 if ( appData.debugMode) {
\r
9866 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9872 CloseHandle(cp->hProcess);
\r
9876 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9880 closesocket(cp->sock);
\r
9885 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9886 closesocket(cp->sock);
\r
9887 closesocket(cp->sock2);
\r
9895 InterruptChildProcess(ProcRef pr)
\r
9899 cp = (ChildProc *) pr;
\r
9900 if (cp == NULL) return;
\r
9901 switch (cp->kind) {
\r
9903 /* The following doesn't work because the chess program
\r
9904 doesn't "have the same console" as WinBoard. Maybe
\r
9905 we could arrange for this even though neither WinBoard
\r
9906 nor the chess program uses a console for stdio */
\r
9907 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9912 /* Can't interrupt */
\r
9916 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9923 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9925 char cmdLine[MSG_SIZ];
\r
9927 if (port[0] == NULLCHAR) {
\r
9928 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9930 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9932 return StartChildProcess(cmdLine, "", pr);
\r
9936 /* Code to open TCP sockets */
\r
9939 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9944 struct sockaddr_in sa, mysa;
\r
9945 struct hostent FAR *hp;
\r
9946 unsigned short uport;
\r
9947 WORD wVersionRequested;
\r
9950 /* Initialize socket DLL */
\r
9951 wVersionRequested = MAKEWORD(1, 1);
\r
9952 err = WSAStartup(wVersionRequested, &wsaData);
\r
9953 if (err != 0) return err;
\r
9956 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9957 err = WSAGetLastError();
\r
9962 /* Bind local address using (mostly) don't-care values.
\r
9964 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9965 mysa.sin_family = AF_INET;
\r
9966 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9967 uport = (unsigned short) 0;
\r
9968 mysa.sin_port = htons(uport);
\r
9969 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9970 == SOCKET_ERROR) {
\r
9971 err = WSAGetLastError();
\r
9976 /* Resolve remote host name */
\r
9977 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9978 if (!(hp = gethostbyname(host))) {
\r
9979 unsigned int b0, b1, b2, b3;
\r
9981 err = WSAGetLastError();
\r
9983 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9984 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9985 hp->h_addrtype = AF_INET;
\r
9987 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9988 hp->h_addr_list[0] = (char *) malloc(4);
\r
9989 hp->h_addr_list[0][0] = (char) b0;
\r
9990 hp->h_addr_list[0][1] = (char) b1;
\r
9991 hp->h_addr_list[0][2] = (char) b2;
\r
9992 hp->h_addr_list[0][3] = (char) b3;
\r
9998 sa.sin_family = hp->h_addrtype;
\r
9999 uport = (unsigned short) atoi(port);
\r
10000 sa.sin_port = htons(uport);
\r
10001 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10003 /* Make connection */
\r
10004 if (connect(s, (struct sockaddr *) &sa,
\r
10005 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10006 err = WSAGetLastError();
\r
10011 /* Prepare return value */
\r
10012 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10013 cp->kind = CPSock;
\r
10015 *pr = (ProcRef *) cp;
\r
10021 OpenCommPort(char *name, ProcRef *pr)
\r
10026 char fullname[MSG_SIZ];
\r
10028 if (*name != '\\')
\r
10029 sprintf(fullname, "\\\\.\\%s", name);
\r
10031 strcpy(fullname, name);
\r
10033 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10034 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10035 if (h == (HANDLE) -1) {
\r
10036 return GetLastError();
\r
10040 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10042 /* Accumulate characters until a 100ms pause, then parse */
\r
10043 ct.ReadIntervalTimeout = 100;
\r
10044 ct.ReadTotalTimeoutMultiplier = 0;
\r
10045 ct.ReadTotalTimeoutConstant = 0;
\r
10046 ct.WriteTotalTimeoutMultiplier = 0;
\r
10047 ct.WriteTotalTimeoutConstant = 0;
\r
10048 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10050 /* Prepare return value */
\r
10051 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10052 cp->kind = CPComm;
\r
10055 *pr = (ProcRef *) cp;
\r
10061 OpenLoopback(ProcRef *pr)
\r
10063 DisplayFatalError("Not implemented", 0, 1);
\r
10069 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10073 SOCKET s, s2, s3;
\r
10074 struct sockaddr_in sa, mysa;
\r
10075 struct hostent FAR *hp;
\r
10076 unsigned short uport;
\r
10077 WORD wVersionRequested;
\r
10080 char stderrPortStr[MSG_SIZ];
\r
10082 /* Initialize socket DLL */
\r
10083 wVersionRequested = MAKEWORD(1, 1);
\r
10084 err = WSAStartup(wVersionRequested, &wsaData);
\r
10085 if (err != 0) return err;
\r
10087 /* Resolve remote host name */
\r
10088 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10089 if (!(hp = gethostbyname(host))) {
\r
10090 unsigned int b0, b1, b2, b3;
\r
10092 err = WSAGetLastError();
\r
10094 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10095 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10096 hp->h_addrtype = AF_INET;
\r
10097 hp->h_length = 4;
\r
10098 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10099 hp->h_addr_list[0] = (char *) malloc(4);
\r
10100 hp->h_addr_list[0][0] = (char) b0;
\r
10101 hp->h_addr_list[0][1] = (char) b1;
\r
10102 hp->h_addr_list[0][2] = (char) b2;
\r
10103 hp->h_addr_list[0][3] = (char) b3;
\r
10109 sa.sin_family = hp->h_addrtype;
\r
10110 uport = (unsigned short) 514;
\r
10111 sa.sin_port = htons(uport);
\r
10112 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10114 /* Bind local socket to unused "privileged" port address
\r
10116 s = INVALID_SOCKET;
\r
10117 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10118 mysa.sin_family = AF_INET;
\r
10119 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10120 for (fromPort = 1023;; fromPort--) {
\r
10121 if (fromPort < 0) {
\r
10123 return WSAEADDRINUSE;
\r
10125 if (s == INVALID_SOCKET) {
\r
10126 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10127 err = WSAGetLastError();
\r
10132 uport = (unsigned short) fromPort;
\r
10133 mysa.sin_port = htons(uport);
\r
10134 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10135 == SOCKET_ERROR) {
\r
10136 err = WSAGetLastError();
\r
10137 if (err == WSAEADDRINUSE) continue;
\r
10141 if (connect(s, (struct sockaddr *) &sa,
\r
10142 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10143 err = WSAGetLastError();
\r
10144 if (err == WSAEADDRINUSE) {
\r
10155 /* Bind stderr local socket to unused "privileged" port address
\r
10157 s2 = INVALID_SOCKET;
\r
10158 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10159 mysa.sin_family = AF_INET;
\r
10160 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10161 for (fromPort = 1023;; fromPort--) {
\r
10162 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10163 if (fromPort < 0) {
\r
10164 (void) closesocket(s);
\r
10166 return WSAEADDRINUSE;
\r
10168 if (s2 == INVALID_SOCKET) {
\r
10169 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10170 err = WSAGetLastError();
\r
10176 uport = (unsigned short) fromPort;
\r
10177 mysa.sin_port = htons(uport);
\r
10178 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10179 == SOCKET_ERROR) {
\r
10180 err = WSAGetLastError();
\r
10181 if (err == WSAEADDRINUSE) continue;
\r
10182 (void) closesocket(s);
\r
10186 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10187 err = WSAGetLastError();
\r
10188 if (err == WSAEADDRINUSE) {
\r
10190 s2 = INVALID_SOCKET;
\r
10193 (void) closesocket(s);
\r
10194 (void) closesocket(s2);
\r
10200 prevStderrPort = fromPort; // remember port used
\r
10201 sprintf(stderrPortStr, "%d", fromPort);
\r
10203 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10204 err = WSAGetLastError();
\r
10205 (void) closesocket(s);
\r
10206 (void) closesocket(s2);
\r
10211 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10212 err = WSAGetLastError();
\r
10213 (void) closesocket(s);
\r
10214 (void) closesocket(s2);
\r
10218 if (*user == NULLCHAR) user = UserName();
\r
10219 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10220 err = WSAGetLastError();
\r
10221 (void) closesocket(s);
\r
10222 (void) closesocket(s2);
\r
10226 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10227 err = WSAGetLastError();
\r
10228 (void) closesocket(s);
\r
10229 (void) closesocket(s2);
\r
10234 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10235 err = WSAGetLastError();
\r
10236 (void) closesocket(s);
\r
10237 (void) closesocket(s2);
\r
10241 (void) closesocket(s2); /* Stop listening */
\r
10243 /* Prepare return value */
\r
10244 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10245 cp->kind = CPRcmd;
\r
10248 *pr = (ProcRef *) cp;
\r
10255 AddInputSource(ProcRef pr, int lineByLine,
\r
10256 InputCallback func, VOIDSTAR closure)
\r
10258 InputSource *is, *is2 = NULL;
\r
10259 ChildProc *cp = (ChildProc *) pr;
\r
10261 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10262 is->lineByLine = lineByLine;
\r
10264 is->closure = closure;
\r
10265 is->second = NULL;
\r
10266 is->next = is->buf;
\r
10267 if (pr == NoProc) {
\r
10268 is->kind = CPReal;
\r
10269 consoleInputSource = is;
\r
10271 is->kind = cp->kind;
\r
10273 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10274 we create all threads suspended so that the is->hThread variable can be
\r
10275 safely assigned, then let the threads start with ResumeThread.
\r
10277 switch (cp->kind) {
\r
10279 is->hFile = cp->hFrom;
\r
10280 cp->hFrom = NULL; /* now owned by InputThread */
\r
10282 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10283 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10287 is->hFile = cp->hFrom;
\r
10288 cp->hFrom = NULL; /* now owned by InputThread */
\r
10290 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10291 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10295 is->sock = cp->sock;
\r
10297 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10298 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10302 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10304 is->sock = cp->sock;
\r
10305 is->second = is2;
\r
10306 is2->sock = cp->sock2;
\r
10307 is2->second = is2;
\r
10309 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10310 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10312 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10313 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10317 if( is->hThread != NULL ) {
\r
10318 ResumeThread( is->hThread );
\r
10321 if( is2 != NULL && is2->hThread != NULL ) {
\r
10322 ResumeThread( is2->hThread );
\r
10326 return (InputSourceRef) is;
\r
10330 RemoveInputSource(InputSourceRef isr)
\r
10334 is = (InputSource *) isr;
\r
10335 is->hThread = NULL; /* tell thread to stop */
\r
10336 CloseHandle(is->hThread);
\r
10337 if (is->second != NULL) {
\r
10338 is->second->hThread = NULL;
\r
10339 CloseHandle(is->second->hThread);
\r
10345 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10348 int outCount = SOCKET_ERROR;
\r
10349 ChildProc *cp = (ChildProc *) pr;
\r
10350 static OVERLAPPED ovl;
\r
10352 if (pr == NoProc) {
\r
10353 ConsoleOutput(message, count, FALSE);
\r
10357 if (ovl.hEvent == NULL) {
\r
10358 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10360 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10362 switch (cp->kind) {
\r
10365 outCount = send(cp->sock, message, count, 0);
\r
10366 if (outCount == SOCKET_ERROR) {
\r
10367 *outError = WSAGetLastError();
\r
10369 *outError = NO_ERROR;
\r
10374 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10375 &dOutCount, NULL)) {
\r
10376 *outError = NO_ERROR;
\r
10377 outCount = (int) dOutCount;
\r
10379 *outError = GetLastError();
\r
10384 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10385 &dOutCount, &ovl);
\r
10386 if (*outError == NO_ERROR) {
\r
10387 outCount = (int) dOutCount;
\r
10395 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10398 /* Ignore delay, not implemented for WinBoard */
\r
10399 return OutputToProcess(pr, message, count, outError);
\r
10404 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10405 char *buf, int count, int error)
\r
10407 DisplayFatalError("Not implemented", 0, 1);
\r
10410 /* see wgamelist.c for Game List functions */
\r
10411 /* see wedittags.c for Edit Tags functions */
\r
10418 char buf[MSG_SIZ];
\r
10421 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10422 f = fopen(buf, "r");
\r
10424 ProcessICSInitScript(f);
\r
10432 StartAnalysisClock()
\r
10434 if (analysisTimerEvent) return;
\r
10435 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10436 (UINT) 2000, NULL);
\r
10440 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10442 static HANDLE hwndText;
\r
10444 static int sizeX, sizeY;
\r
10445 int newSizeX, newSizeY, flags;
\r
10448 switch (message) {
\r
10449 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10450 /* Initialize the dialog items */
\r
10451 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10452 SetWindowText(hDlg, analysisTitle);
\r
10453 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10454 /* Size and position the dialog */
\r
10455 if (!analysisDialog) {
\r
10456 analysisDialog = hDlg;
\r
10457 flags = SWP_NOZORDER;
\r
10458 GetClientRect(hDlg, &rect);
\r
10459 sizeX = rect.right;
\r
10460 sizeY = rect.bottom;
\r
10461 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10462 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10463 WINDOWPLACEMENT wp;
\r
10464 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10465 wp.length = sizeof(WINDOWPLACEMENT);
\r
10467 wp.showCmd = SW_SHOW;
\r
10468 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10469 wp.rcNormalPosition.left = analysisX;
\r
10470 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10471 wp.rcNormalPosition.top = analysisY;
\r
10472 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10473 SetWindowPlacement(hDlg, &wp);
\r
10475 GetClientRect(hDlg, &rect);
\r
10476 newSizeX = rect.right;
\r
10477 newSizeY = rect.bottom;
\r
10478 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10479 newSizeX, newSizeY);
\r
10480 sizeX = newSizeX;
\r
10481 sizeY = newSizeY;
\r
10486 case WM_COMMAND: /* message: received a command */
\r
10487 switch (LOWORD(wParam)) {
\r
10489 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10490 ExitAnalyzeMode();
\r
10502 newSizeX = LOWORD(lParam);
\r
10503 newSizeY = HIWORD(lParam);
\r
10504 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10505 sizeX = newSizeX;
\r
10506 sizeY = newSizeY;
\r
10509 case WM_GETMINMAXINFO:
\r
10510 /* Prevent resizing window too small */
\r
10511 mmi = (MINMAXINFO *) lParam;
\r
10512 mmi->ptMinTrackSize.x = 100;
\r
10513 mmi->ptMinTrackSize.y = 100;
\r
10520 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10522 highlightInfo.sq[0].x = fromX;
\r
10523 highlightInfo.sq[0].y = fromY;
\r
10524 highlightInfo.sq[1].x = toX;
\r
10525 highlightInfo.sq[1].y = toY;
\r
10529 ClearHighlights()
\r
10531 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10532 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10536 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10538 premoveHighlightInfo.sq[0].x = fromX;
\r
10539 premoveHighlightInfo.sq[0].y = fromY;
\r
10540 premoveHighlightInfo.sq[1].x = toX;
\r
10541 premoveHighlightInfo.sq[1].y = toY;
\r
10545 ClearPremoveHighlights()
\r
10547 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10548 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10552 ShutDownFrontEnd()
\r
10554 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10555 DeleteClipboardTempFiles();
\r
10561 if (IsIconic(hwndMain))
\r
10562 ShowWindow(hwndMain, SW_RESTORE);
\r
10564 SetActiveWindow(hwndMain);
\r
10568 * Prototypes for animation support routines
\r
10570 static void ScreenSquare(int column, int row, POINT * pt);
\r
10571 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10572 POINT frames[], int * nFrames);
\r
10576 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10577 { // [HGM] atomic: animate blast wave
\r
10579 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10580 explodeInfo.fromX = fromX;
\r
10581 explodeInfo.fromY = fromY;
\r
10582 explodeInfo.toX = toX;
\r
10583 explodeInfo.toY = toY;
\r
10584 for(i=1; i<nFrames; i++) {
\r
10585 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10586 DrawPosition(FALSE, NULL);
\r
10587 Sleep(appData.animSpeed);
\r
10589 explodeInfo.radius = 0;
\r
10590 DrawPosition(TRUE, NULL);
\r
10593 #define kFactor 4
\r
10596 AnimateMove(board, fromX, fromY, toX, toY)
\r
10603 ChessSquare piece;
\r
10604 POINT start, finish, mid;
\r
10605 POINT frames[kFactor * 2 + 1];
\r
10608 if (!appData.animate) return;
\r
10609 if (doingSizing) return;
\r
10610 if (fromY < 0 || fromX < 0) return;
\r
10611 piece = board[fromY][fromX];
\r
10612 if (piece >= EmptySquare) return;
\r
10614 ScreenSquare(fromX, fromY, &start);
\r
10615 ScreenSquare(toX, toY, &finish);
\r
10617 /* All pieces except knights move in straight line */
\r
10618 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10619 mid.x = start.x + (finish.x - start.x) / 2;
\r
10620 mid.y = start.y + (finish.y - start.y) / 2;
\r
10622 /* Knight: make diagonal movement then straight */
\r
10623 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10624 mid.x = start.x + (finish.x - start.x) / 2;
\r
10625 mid.y = finish.y;
\r
10627 mid.x = finish.x;
\r
10628 mid.y = start.y + (finish.y - start.y) / 2;
\r
10632 /* Don't use as many frames for very short moves */
\r
10633 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10634 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10636 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10638 animInfo.from.x = fromX;
\r
10639 animInfo.from.y = fromY;
\r
10640 animInfo.to.x = toX;
\r
10641 animInfo.to.y = toY;
\r
10642 animInfo.lastpos = start;
\r
10643 animInfo.piece = piece;
\r
10644 for (n = 0; n < nFrames; n++) {
\r
10645 animInfo.pos = frames[n];
\r
10646 DrawPosition(FALSE, NULL);
\r
10647 animInfo.lastpos = animInfo.pos;
\r
10648 Sleep(appData.animSpeed);
\r
10650 animInfo.pos = finish;
\r
10651 DrawPosition(FALSE, NULL);
\r
10652 animInfo.piece = EmptySquare;
\r
10653 if(gameInfo.variant == VariantAtomic &&
\r
10654 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10655 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10658 /* Convert board position to corner of screen rect and color */
\r
10661 ScreenSquare(column, row, pt)
\r
10662 int column; int row; POINT * pt;
\r
10665 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10666 pt->y = lineGap + row * (squareSize + lineGap);
\r
10668 pt->x = lineGap + column * (squareSize + lineGap);
\r
10669 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10673 /* Generate a series of frame coords from start->mid->finish.
\r
10674 The movement rate doubles until the half way point is
\r
10675 reached, then halves back down to the final destination,
\r
10676 which gives a nice slow in/out effect. The algorithmn
\r
10677 may seem to generate too many intermediates for short
\r
10678 moves, but remember that the purpose is to attract the
\r
10679 viewers attention to the piece about to be moved and
\r
10680 then to where it ends up. Too few frames would be less
\r
10684 Tween(start, mid, finish, factor, frames, nFrames)
\r
10685 POINT * start; POINT * mid;
\r
10686 POINT * finish; int factor;
\r
10687 POINT frames[]; int * nFrames;
\r
10689 int n, fraction = 1, count = 0;
\r
10691 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10692 for (n = 0; n < factor; n++)
\r
10694 for (n = 0; n < factor; n++) {
\r
10695 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10696 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10698 fraction = fraction / 2;
\r
10702 frames[count] = *mid;
\r
10705 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10707 for (n = 0; n < factor; n++) {
\r
10708 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10709 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10711 fraction = fraction * 2;
\r
10713 *nFrames = count;
\r
10717 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10719 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10721 EvalGraphSet( first, last, current, pvInfoList );
\r
10724 void SetProgramStats( FrontEndProgramStats * stats )
\r
10726 EngineOutputUpdate( stats );
\r