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
4843 EventToSquare(int x)
\r
4850 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4852 x /= (squareSize + lineGap);
\r
4853 if (x >= BOARD_SIZE)
\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 /* Event handler for mouse messages */
\r
4897 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4901 static int recursive = 0;
\r
4903 // BOOLEAN needsRedraw = FALSE;
\r
4904 BOOLEAN saveAnimate;
\r
4905 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4906 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4907 ChessMove moveType;
\r
4910 if (message == WM_MBUTTONUP) {
\r
4911 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4912 to the middle button: we simulate pressing the left button too!
\r
4914 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4915 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4921 pt.x = LOWORD(lParam);
\r
4922 pt.y = HIWORD(lParam);
\r
4923 x = EventToSquare(pt.x - boardRect.left);
\r
4924 y = EventToSquare(pt.y - boardRect.top);
\r
4925 if (!flipView && y >= 0) {
\r
4926 y = BOARD_HEIGHT - 1 - y;
\r
4928 if (flipView && x >= 0) {
\r
4929 x = BOARD_WIDTH - 1 - x;
\r
4932 switch (message) {
\r
4933 case WM_LBUTTONDOWN:
\r
4934 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4935 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4936 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4937 if(gameInfo.holdingsWidth &&
\r
4938 (WhiteOnMove(currentMove)
\r
4939 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4940 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4941 // click in right holdings, for determining promotion piece
\r
4942 ChessSquare p = boards[currentMove][y][x];
\r
4943 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4944 if(p != EmptySquare) {
\r
4945 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4946 fromX = fromY = -1;
\r
4950 DrawPosition(FALSE, boards[currentMove]);
\r
4954 sameAgain = FALSE;
\r
4956 /* Downclick vertically off board; check if on clock */
\r
4957 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4958 if (gameMode == EditPosition) {
\r
4959 SetWhiteToPlayEvent();
\r
4960 } else if (gameMode == IcsPlayingBlack ||
\r
4961 gameMode == MachinePlaysWhite) {
\r
4963 } else if (gameMode == EditGame) {
\r
4964 AdjustClock(flipClock, -1);
\r
4966 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4967 if (gameMode == EditPosition) {
\r
4968 SetBlackToPlayEvent();
\r
4969 } else if (gameMode == IcsPlayingWhite ||
\r
4970 gameMode == MachinePlaysBlack) {
\r
4972 } else if (gameMode == EditGame) {
\r
4973 AdjustClock(!flipClock, -1);
\r
4976 if (!appData.highlightLastMove) {
\r
4977 ClearHighlights();
\r
4978 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4980 fromX = fromY = -1;
\r
4981 dragInfo.start.x = dragInfo.start.y = -1;
\r
4982 dragInfo.from = dragInfo.start;
\r
4984 } else if (x < 0 || y < 0
\r
4985 /* [HGM] block clicks between board and holdings */
\r
4986 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4987 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4988 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4989 /* EditPosition, empty square, or different color piece;
\r
4990 click-click move is possible */
\r
4993 } else if (fromX == x && fromY == y) {
\r
4994 /* Downclick on same square again */
\r
4995 ClearHighlights();
\r
4996 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4997 sameAgain = TRUE;
\r
4998 } else if (fromX != -1 &&
\r
4999 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5001 /* Downclick on different square. */
\r
5002 /* [HGM] if on holdings file, should count as new first click ! */
\r
5003 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5006 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5007 to make sure move is legal before showing promotion popup */
\r
5008 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5009 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5010 fromX = fromY = -1;
\r
5011 ClearHighlights();
\r
5012 DrawPosition(FALSE, boards[currentMove]);
\r
5015 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5016 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5017 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5018 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5019 appData.alwaysPromoteToQueen)) {
\r
5020 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5021 if (!appData.highlightLastMove) {
\r
5022 ClearHighlights();
\r
5023 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5026 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5027 SetHighlights(fromX, fromY, toX, toY);
\r
5028 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5029 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5030 If promotion to Q is legal, all are legal! */
\r
5031 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5032 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5033 // kludge to temporarily execute move on display, without promoting yet
\r
5034 promotionChoice = TRUE;
\r
5035 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5036 boards[currentMove][toY][toX] = p;
\r
5037 DrawPosition(FALSE, boards[currentMove]);
\r
5038 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5039 boards[currentMove][toY][toX] = q;
\r
5040 DisplayMessage("Select piece from holdings", "");
\r
5042 PromotionPopup(hwnd);
\r
5044 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5045 if (appData.animate || appData.highlightLastMove) {
\r
5046 SetHighlights(fromX, fromY, toX, toY);
\r
5048 ClearHighlights();
\r
5050 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5051 if (appData.animate && !appData.highlightLastMove) {
\r
5052 ClearHighlights();
\r
5053 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5056 fromX = fromY = -1;
\r
5060 if (gotPremove && moveType != Comment) {
\r
5061 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5062 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5063 } else ClearHighlights();
\r
5064 fromX = fromY = -1;
\r
5065 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5066 if(moveType != Comment) break;
\r
5068 /* First downclick, or restart on a square with same color piece */
\r
5069 if (!frozen && OKToStartUserMove(x, y)) {
\r
5072 dragInfo.lastpos = pt;
\r
5073 dragInfo.from.x = fromX;
\r
5074 dragInfo.from.y = fromY;
\r
5075 dragInfo.start = dragInfo.from;
\r
5076 SetCapture(hwndMain);
\r
5078 fromX = fromY = -1;
\r
5079 dragInfo.start.x = dragInfo.start.y = -1;
\r
5080 dragInfo.from = dragInfo.start;
\r
5081 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5085 case WM_LBUTTONUP:
\r
5087 if (fromX == -1) break;
\r
5088 if (x == fromX && y == fromY) {
\r
5089 dragInfo.from.x = dragInfo.from.y = -1;
\r
5090 /* Upclick on same square */
\r
5092 /* Clicked same square twice: abort click-click move */
\r
5093 fromX = fromY = -1;
\r
5095 ClearPremoveHighlights();
\r
5097 /* First square clicked: start click-click move */
\r
5098 SetHighlights(fromX, fromY, -1, -1);
\r
5100 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5101 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5102 /* Errant click; ignore */
\r
5105 /* Finish drag move. */
\r
5106 if (appData.debugMode) {
\r
5107 fprintf(debugFP, "release\n");
\r
5109 dragInfo.from.x = dragInfo.from.y = -1;
\r
5112 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5113 appData.animate = appData.animate && !appData.animateDragging;
\r
5114 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5115 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5116 fromX = fromY = -1;
\r
5117 ClearHighlights();
\r
5118 DrawPosition(FALSE, boards[currentMove]);
\r
5119 appData.animate = saveAnimate;
\r
5122 if(moveType != ImpossibleMove) {
\r
5123 /* [HGM] use move type to determine if move is promotion.
\r
5124 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5125 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5126 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5127 appData.alwaysPromoteToQueen))
\r
5128 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5130 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5131 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5132 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5133 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5134 // kludge to temporarily execute move on display, wthout promotng yet
\r
5135 promotionChoice = TRUE;
\r
5136 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5137 boards[currentMove][toY][toX] = p;
\r
5138 DrawPosition(FALSE, boards[currentMove]);
\r
5139 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5140 boards[currentMove][toY][toX] = q;
\r
5141 appData.animate = saveAnimate;
\r
5142 DisplayMessage("Select piece from holdings", "");
\r
5145 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5147 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5148 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5149 moveType == WhiteCapturesEnPassant ||
\r
5150 moveType == BlackCapturesEnPassant ) )
\r
5151 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5152 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5155 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5156 appData.animate = saveAnimate;
\r
5157 fromX = fromY = -1;
\r
5158 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5159 ClearHighlights();
\r
5161 if (appData.animate || appData.animateDragging ||
\r
5162 appData.highlightDragging || gotPremove) {
\r
5163 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5166 dragInfo.start.x = dragInfo.start.y = -1;
\r
5167 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5170 case WM_MOUSEMOVE:
\r
5171 if ((appData.animateDragging || appData.highlightDragging)
\r
5172 && (wParam & MK_LBUTTON)
\r
5173 && dragInfo.from.x >= 0)
\r
5175 BOOL full_repaint = FALSE;
\r
5177 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5178 if (appData.animateDragging) {
\r
5179 dragInfo.pos = pt;
\r
5181 if (appData.highlightDragging) {
\r
5182 SetHighlights(fromX, fromY, x, y);
\r
5183 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5184 full_repaint = TRUE;
\r
5188 DrawPosition( full_repaint, NULL);
\r
5190 dragInfo.lastpos = dragInfo.pos;
\r
5194 case WM_MOUSEWHEEL: // [DM]
\r
5195 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5196 /* Mouse Wheel is being rolled forward
\r
5197 * Play moves forward
\r
5199 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5200 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5201 /* Mouse Wheel is being rolled backward
\r
5202 * Play moves backward
\r
5204 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5205 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5209 case WM_MBUTTONDOWN:
\r
5210 case WM_RBUTTONDOWN:
\r
5213 fromX = fromY = -1;
\r
5214 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5215 dragInfo.start.x = dragInfo.start.y = -1;
\r
5216 dragInfo.from = dragInfo.start;
\r
5217 dragInfo.lastpos = dragInfo.pos;
\r
5218 if (appData.highlightDragging) {
\r
5219 ClearHighlights();
\r
5222 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5223 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5224 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5225 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5226 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5229 DrawPosition(TRUE, NULL);
\r
5231 switch (gameMode) {
\r
5232 case EditPosition:
\r
5233 case IcsExamining:
\r
5234 if (x < 0 || y < 0) break;
\r
5237 if (message == WM_MBUTTONDOWN) {
\r
5238 buttonCount = 3; /* even if system didn't think so */
\r
5239 if (wParam & MK_SHIFT)
\r
5240 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5242 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5243 } else { /* message == WM_RBUTTONDOWN */
\r
5244 /* Just have one menu, on the right button. Windows users don't
\r
5245 think to try the middle one, and sometimes other software steals
\r
5246 it, or it doesn't really exist. */
\r
5247 if(gameInfo.variant != VariantShogi)
\r
5248 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5250 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5253 case IcsPlayingWhite:
\r
5254 case IcsPlayingBlack:
\r
5256 case MachinePlaysWhite:
\r
5257 case MachinePlaysBlack:
\r
5258 if (appData.testLegality &&
\r
5259 gameInfo.variant != VariantBughouse &&
\r
5260 gameInfo.variant != VariantCrazyhouse) break;
\r
5261 if (x < 0 || y < 0) break;
\r
5264 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5265 SetupDropMenu(hmenu);
\r
5266 MenuPopup(hwnd, pt, hmenu, -1);
\r
5277 /* Preprocess messages for buttons in main window */
\r
5279 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5281 int id = GetWindowLong(hwnd, GWL_ID);
\r
5284 for (i=0; i<N_BUTTONS; i++) {
\r
5285 if (buttonDesc[i].id == id) break;
\r
5287 if (i == N_BUTTONS) return 0;
\r
5288 switch (message) {
\r
5293 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5294 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5301 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5304 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5305 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5306 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5307 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5309 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5311 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5312 PopUpMoveDialog((char)wParam);
\r
5318 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5321 /* Process messages for Promotion dialog box */
\r
5323 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5327 switch (message) {
\r
5328 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5329 /* Center the dialog over the application window */
\r
5330 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5331 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5332 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5333 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5334 SW_SHOW : SW_HIDE);
\r
5335 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5336 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5337 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5338 PieceToChar(WhiteAngel) != '~') ||
\r
5339 (PieceToChar(BlackAngel) >= 'A' &&
\r
5340 PieceToChar(BlackAngel) != '~') ) ?
\r
5341 SW_SHOW : SW_HIDE);
\r
5342 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5343 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5344 PieceToChar(WhiteMarshall) != '~') ||
\r
5345 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5346 PieceToChar(BlackMarshall) != '~') ) ?
\r
5347 SW_SHOW : SW_HIDE);
\r
5348 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5349 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5350 gameInfo.variant != VariantShogi ?
\r
5351 SW_SHOW : SW_HIDE);
\r
5352 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5353 gameInfo.variant != VariantShogi ?
\r
5354 SW_SHOW : SW_HIDE);
\r
5355 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5356 gameInfo.variant == VariantShogi ?
\r
5357 SW_SHOW : SW_HIDE);
\r
5358 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5359 gameInfo.variant == VariantShogi ?
\r
5360 SW_SHOW : SW_HIDE);
\r
5361 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5362 gameInfo.variant == VariantSuper ?
\r
5363 SW_SHOW : SW_HIDE);
\r
5366 case WM_COMMAND: /* message: received a command */
\r
5367 switch (LOWORD(wParam)) {
\r
5369 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5370 ClearHighlights();
\r
5371 DrawPosition(FALSE, NULL);
\r
5374 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5377 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5380 promoChar = PieceToChar(BlackRook);
\r
5383 promoChar = PieceToChar(BlackBishop);
\r
5385 case PB_Chancellor:
\r
5386 promoChar = PieceToChar(BlackMarshall);
\r
5388 case PB_Archbishop:
\r
5389 promoChar = PieceToChar(BlackAngel);
\r
5392 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5397 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5398 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5399 only show the popup when we are already sure the move is valid or
\r
5400 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5401 will figure out it is a promotion from the promoChar. */
\r
5402 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5403 if (!appData.highlightLastMove) {
\r
5404 ClearHighlights();
\r
5405 DrawPosition(FALSE, NULL);
\r
5412 /* Pop up promotion dialog */
\r
5414 PromotionPopup(HWND hwnd)
\r
5418 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5419 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5420 hwnd, (DLGPROC)lpProc);
\r
5421 FreeProcInstance(lpProc);
\r
5424 /* Toggle ShowThinking */
\r
5426 ToggleShowThinking()
\r
5428 appData.showThinking = !appData.showThinking;
\r
5429 ShowThinkingEvent();
\r
5433 LoadGameDialog(HWND hwnd, char* title)
\r
5437 char fileTitle[MSG_SIZ];
\r
5438 f = OpenFileDialog(hwnd, "rb", "",
\r
5439 appData.oldSaveStyle ? "gam" : "pgn",
\r
5441 title, &number, fileTitle, NULL);
\r
5443 cmailMsgLoaded = FALSE;
\r
5444 if (number == 0) {
\r
5445 int error = GameListBuild(f);
\r
5447 DisplayError("Cannot build game list", error);
\r
5448 } else if (!ListEmpty(&gameList) &&
\r
5449 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5450 GameListPopUp(f, fileTitle);
\r
5453 GameListDestroy();
\r
5456 LoadGame(f, number, fileTitle, FALSE);
\r
5460 void UpdateICSWidth(HWND hText)
\r
5465 HFONT hfont, hold_font;
\r
5466 LONG old_width, new_width;
\r
5468 // get the text metrics
\r
5469 hdc = GetDC(hText);
\r
5470 hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);
\r
5471 hold_font = SelectObject(hdc, hfont);
\r
5472 GetTextMetrics(hdc, &tm);
\r
5473 SelectObject(hdc, hold_font);
\r
5474 DeleteObject(hfont);
\r
5475 ReleaseDC(hText, hdc);
\r
5477 // get the rectangle
\r
5478 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5480 // update the width
\r
5481 new_width = (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5482 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5483 if (new_width != old_width)
\r
5485 ics_update_width(new_width);
\r
5486 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5491 ChangedConsoleFont()
\r
5494 CHARRANGE tmpsel, sel;
\r
5495 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5496 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5497 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5500 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5501 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5502 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5503 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5504 * size. This was undocumented in the version of MSVC++ that I had
\r
5505 * when I wrote the code, but is apparently documented now.
\r
5507 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5508 cfmt.bCharSet = f->lf.lfCharSet;
\r
5509 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5510 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5511 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5512 /* Why are the following seemingly needed too? */
\r
5513 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5514 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5515 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5517 tmpsel.cpMax = -1; /*999999?*/
\r
5518 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5519 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5520 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5521 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5523 paraf.cbSize = sizeof(paraf);
\r
5524 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5525 paraf.dxStartIndent = 0;
\r
5526 paraf.dxOffset = WRAP_INDENT;
\r
5527 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5528 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5529 UpdateICSWidth(hText);
\r
5532 /*---------------------------------------------------------------------------*\
\r
5534 * Window Proc for main window
\r
5536 \*---------------------------------------------------------------------------*/
\r
5538 /* Process messages for main window, etc. */
\r
5540 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5543 int wmId, wmEvent;
\r
5547 char fileTitle[MSG_SIZ];
\r
5548 char buf[MSG_SIZ];
\r
5549 static SnapData sd;
\r
5551 switch (message) {
\r
5553 case WM_PAINT: /* message: repaint portion of window */
\r
5557 case WM_ERASEBKGND:
\r
5558 if (IsIconic(hwnd)) {
\r
5559 /* Cheat; change the message */
\r
5560 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5562 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5566 case WM_LBUTTONDOWN:
\r
5567 case WM_MBUTTONDOWN:
\r
5568 case WM_RBUTTONDOWN:
\r
5569 case WM_LBUTTONUP:
\r
5570 case WM_MBUTTONUP:
\r
5571 case WM_RBUTTONUP:
\r
5572 case WM_MOUSEMOVE:
\r
5573 case WM_MOUSEWHEEL:
\r
5574 MouseEvent(hwnd, message, wParam, lParam);
\r
5577 JAWS_KB_NAVIGATION
\r
5581 JAWS_ALT_INTERCEPT
\r
5583 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5584 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5585 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5586 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5588 SendMessage(h, message, wParam, lParam);
\r
5589 } else if(lParam != KF_REPEAT) {
\r
5590 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5591 PopUpMoveDialog((char)wParam);
\r
5592 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5593 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5598 case WM_PALETTECHANGED:
\r
5599 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5601 HDC hdc = GetDC(hwndMain);
\r
5602 SelectPalette(hdc, hPal, TRUE);
\r
5603 nnew = RealizePalette(hdc);
\r
5605 paletteChanged = TRUE;
\r
5606 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5608 ReleaseDC(hwnd, hdc);
\r
5612 case WM_QUERYNEWPALETTE:
\r
5613 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5615 HDC hdc = GetDC(hwndMain);
\r
5616 paletteChanged = FALSE;
\r
5617 SelectPalette(hdc, hPal, FALSE);
\r
5618 nnew = RealizePalette(hdc);
\r
5620 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5622 ReleaseDC(hwnd, hdc);
\r
5627 case WM_COMMAND: /* message: command from application menu */
\r
5628 wmId = LOWORD(wParam);
\r
5629 wmEvent = HIWORD(wParam);
\r
5634 EngineOutputPopDown();
\r
5635 SAY("new game enter a move to play against the computer with white");
\r
5638 case IDM_NewGameFRC:
\r
5639 if( NewGameFRC() == 0 ) {
\r
5641 EngineOutputPopDown();
\r
5645 case IDM_NewVariant:
\r
5646 NewVariantPopup(hwnd);
\r
5649 case IDM_LoadGame:
\r
5650 LoadGameDialog(hwnd, "Load Game from File");
\r
5653 case IDM_LoadNextGame:
\r
5657 case IDM_LoadPrevGame:
\r
5661 case IDM_ReloadGame:
\r
5665 case IDM_LoadPosition:
\r
5666 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5667 Reset(FALSE, TRUE);
\r
5670 f = OpenFileDialog(hwnd, "rb", "",
\r
5671 appData.oldSaveStyle ? "pos" : "fen",
\r
5673 "Load Position from File", &number, fileTitle, NULL);
\r
5675 LoadPosition(f, number, fileTitle);
\r
5679 case IDM_LoadNextPosition:
\r
5680 ReloadPosition(1);
\r
5683 case IDM_LoadPrevPosition:
\r
5684 ReloadPosition(-1);
\r
5687 case IDM_ReloadPosition:
\r
5688 ReloadPosition(0);
\r
5691 case IDM_SaveGame:
\r
5692 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5693 f = OpenFileDialog(hwnd, "a", defName,
\r
5694 appData.oldSaveStyle ? "gam" : "pgn",
\r
5696 "Save Game to File", NULL, fileTitle, NULL);
\r
5698 SaveGame(f, 0, "");
\r
5702 case IDM_SavePosition:
\r
5703 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5704 f = OpenFileDialog(hwnd, "a", defName,
\r
5705 appData.oldSaveStyle ? "pos" : "fen",
\r
5707 "Save Position to File", NULL, fileTitle, NULL);
\r
5709 SavePosition(f, 0, "");
\r
5713 case IDM_SaveDiagram:
\r
5714 defName = "diagram";
\r
5715 f = OpenFileDialog(hwnd, "wb", defName,
\r
5718 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5724 case IDM_CopyGame:
\r
5725 CopyGameToClipboard();
\r
5728 case IDM_PasteGame:
\r
5729 PasteGameFromClipboard();
\r
5732 case IDM_CopyGameListToClipboard:
\r
5733 CopyGameListToClipboard();
\r
5736 /* [AS] Autodetect FEN or PGN data */
\r
5737 case IDM_PasteAny:
\r
5738 PasteGameOrFENFromClipboard();
\r
5741 /* [AS] Move history */
\r
5742 case IDM_ShowMoveHistory:
\r
5743 if( MoveHistoryIsUp() ) {
\r
5744 MoveHistoryPopDown();
\r
5747 MoveHistoryPopUp();
\r
5751 /* [AS] Eval graph */
\r
5752 case IDM_ShowEvalGraph:
\r
5753 if( EvalGraphIsUp() ) {
\r
5754 EvalGraphPopDown();
\r
5758 SetFocus(hwndMain);
\r
5762 /* [AS] Engine output */
\r
5763 case IDM_ShowEngineOutput:
\r
5764 if( EngineOutputIsUp() ) {
\r
5765 EngineOutputPopDown();
\r
5768 EngineOutputPopUp();
\r
5772 /* [AS] User adjudication */
\r
5773 case IDM_UserAdjudication_White:
\r
5774 UserAdjudicationEvent( +1 );
\r
5777 case IDM_UserAdjudication_Black:
\r
5778 UserAdjudicationEvent( -1 );
\r
5781 case IDM_UserAdjudication_Draw:
\r
5782 UserAdjudicationEvent( 0 );
\r
5785 /* [AS] Game list options dialog */
\r
5786 case IDM_GameListOptions:
\r
5787 GameListOptions();
\r
5794 case IDM_CopyPosition:
\r
5795 CopyFENToClipboard();
\r
5798 case IDM_PastePosition:
\r
5799 PasteFENFromClipboard();
\r
5802 case IDM_MailMove:
\r
5806 case IDM_ReloadCMailMsg:
\r
5807 Reset(TRUE, TRUE);
\r
5808 ReloadCmailMsgEvent(FALSE);
\r
5811 case IDM_Minimize:
\r
5812 ShowWindow(hwnd, SW_MINIMIZE);
\r
5819 case IDM_MachineWhite:
\r
5820 MachineWhiteEvent();
\r
5822 * refresh the tags dialog only if it's visible
\r
5824 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5826 tags = PGNTags(&gameInfo);
\r
5827 TagsPopUp(tags, CmailMsg());
\r
5830 SAY("computer starts playing white");
\r
5833 case IDM_MachineBlack:
\r
5834 MachineBlackEvent();
\r
5836 * refresh the tags dialog only if it's visible
\r
5838 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5840 tags = PGNTags(&gameInfo);
\r
5841 TagsPopUp(tags, CmailMsg());
\r
5844 SAY("computer starts playing black");
\r
5847 case IDM_TwoMachines:
\r
5848 TwoMachinesEvent();
\r
5850 * refresh the tags dialog only if it's visible
\r
5852 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5854 tags = PGNTags(&gameInfo);
\r
5855 TagsPopUp(tags, CmailMsg());
\r
5858 SAY("programs start playing each other");
\r
5861 case IDM_AnalysisMode:
\r
5862 if (!first.analysisSupport) {
\r
5863 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5864 DisplayError(buf, 0);
\r
5866 SAY("analyzing current position");
\r
5867 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5868 if (appData.icsActive) {
\r
5869 if (gameMode != IcsObserving) {
\r
5870 sprintf(buf, "You are not observing a game");
\r
5871 DisplayError(buf, 0);
\r
5872 /* secure check */
\r
5873 if (appData.icsEngineAnalyze) {
\r
5874 if (appData.debugMode)
\r
5875 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5876 ExitAnalyzeMode();
\r
5882 /* if enable, user want disable icsEngineAnalyze */
\r
5883 if (appData.icsEngineAnalyze) {
\r
5884 ExitAnalyzeMode();
\r
5888 appData.icsEngineAnalyze = TRUE;
\r
5889 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5892 if (!appData.showThinking) ToggleShowThinking();
\r
5893 AnalyzeModeEvent();
\r
5897 case IDM_AnalyzeFile:
\r
5898 if (!first.analysisSupport) {
\r
5899 char buf[MSG_SIZ];
\r
5900 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5901 DisplayError(buf, 0);
\r
5903 if (!appData.showThinking) ToggleShowThinking();
\r
5904 AnalyzeFileEvent();
\r
5905 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5906 AnalysisPeriodicEvent(1);
\r
5910 case IDM_IcsClient:
\r
5914 case IDM_EditGame:
\r
5919 case IDM_EditPosition:
\r
5920 EditPositionEvent();
\r
5921 SAY("to set up a position type a FEN");
\r
5924 case IDM_Training:
\r
5928 case IDM_ShowGameList:
\r
5929 ShowGameListProc();
\r
5932 case IDM_EditTags:
\r
5936 case IDM_EditComment:
\r
5937 if (commentDialogUp && editComment) {
\r
5940 EditCommentEvent();
\r
5960 case IDM_CallFlag:
\r
5980 case IDM_StopObserving:
\r
5981 StopObservingEvent();
\r
5984 case IDM_StopExamining:
\r
5985 StopExaminingEvent();
\r
5988 case IDM_TypeInMove:
\r
5989 PopUpMoveDialog('\000');
\r
5992 case IDM_TypeInName:
\r
5993 PopUpNameDialog('\000');
\r
5996 case IDM_Backward:
\r
5998 SetFocus(hwndMain);
\r
6005 SetFocus(hwndMain);
\r
6010 SetFocus(hwndMain);
\r
6015 SetFocus(hwndMain);
\r
6022 case IDM_TruncateGame:
\r
6023 TruncateGameEvent();
\r
6030 case IDM_RetractMove:
\r
6031 RetractMoveEvent();
\r
6034 case IDM_FlipView:
\r
6035 flipView = !flipView;
\r
6036 DrawPosition(FALSE, NULL);
\r
6039 case IDM_FlipClock:
\r
6040 flipClock = !flipClock;
\r
6041 DisplayBothClocks();
\r
6042 DrawPosition(FALSE, NULL);
\r
6045 case IDM_MuteSounds:
\r
6046 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6047 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6048 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6051 case IDM_GeneralOptions:
\r
6052 GeneralOptionsPopup(hwnd);
\r
6053 DrawPosition(TRUE, NULL);
\r
6056 case IDM_BoardOptions:
\r
6057 BoardOptionsPopup(hwnd);
\r
6060 case IDM_EnginePlayOptions:
\r
6061 EnginePlayOptionsPopup(hwnd);
\r
6064 case IDM_Engine1Options:
\r
6065 EngineOptionsPopup(hwnd, &first);
\r
6068 case IDM_Engine2Options:
\r
6069 EngineOptionsPopup(hwnd, &second);
\r
6072 case IDM_OptionsUCI:
\r
6073 UciOptionsPopup(hwnd);
\r
6076 case IDM_IcsOptions:
\r
6077 IcsOptionsPopup(hwnd);
\r
6081 FontsOptionsPopup(hwnd);
\r
6085 SoundOptionsPopup(hwnd);
\r
6088 case IDM_CommPort:
\r
6089 CommPortOptionsPopup(hwnd);
\r
6092 case IDM_LoadOptions:
\r
6093 LoadOptionsPopup(hwnd);
\r
6096 case IDM_SaveOptions:
\r
6097 SaveOptionsPopup(hwnd);
\r
6100 case IDM_TimeControl:
\r
6101 TimeControlOptionsPopup(hwnd);
\r
6104 case IDM_SaveSettings:
\r
6105 SaveSettings(settingsFileName);
\r
6108 case IDM_SaveSettingsOnExit:
\r
6109 saveSettingsOnExit = !saveSettingsOnExit;
\r
6110 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6111 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6112 MF_CHECKED : MF_UNCHECKED));
\r
6123 case IDM_AboutGame:
\r
6128 appData.debugMode = !appData.debugMode;
\r
6129 if (appData.debugMode) {
\r
6130 char dir[MSG_SIZ];
\r
6131 GetCurrentDirectory(MSG_SIZ, dir);
\r
6132 SetCurrentDirectory(installDir);
\r
6133 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6134 SetCurrentDirectory(dir);
\r
6135 setbuf(debugFP, NULL);
\r
6142 case IDM_HELPCONTENTS:
\r
6143 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6144 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6145 MessageBox (GetFocus(),
\r
6146 "Unable to activate help",
\r
6147 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6151 case IDM_HELPSEARCH:
\r
6152 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6153 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6154 MessageBox (GetFocus(),
\r
6155 "Unable to activate help",
\r
6156 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6160 case IDM_HELPHELP:
\r
6161 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6162 MessageBox (GetFocus(),
\r
6163 "Unable to activate help",
\r
6164 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6169 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6171 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6172 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6173 FreeProcInstance(lpProc);
\r
6176 case IDM_DirectCommand1:
\r
6177 AskQuestionEvent("Direct Command",
\r
6178 "Send to chess program:", "", "1");
\r
6180 case IDM_DirectCommand2:
\r
6181 AskQuestionEvent("Direct Command",
\r
6182 "Send to second chess program:", "", "2");
\r
6185 case EP_WhitePawn:
\r
6186 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6187 fromX = fromY = -1;
\r
6190 case EP_WhiteKnight:
\r
6191 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6192 fromX = fromY = -1;
\r
6195 case EP_WhiteBishop:
\r
6196 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6197 fromX = fromY = -1;
\r
6200 case EP_WhiteRook:
\r
6201 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6202 fromX = fromY = -1;
\r
6205 case EP_WhiteQueen:
\r
6206 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6207 fromX = fromY = -1;
\r
6210 case EP_WhiteFerz:
\r
6211 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6212 fromX = fromY = -1;
\r
6215 case EP_WhiteWazir:
\r
6216 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6217 fromX = fromY = -1;
\r
6220 case EP_WhiteAlfil:
\r
6221 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6222 fromX = fromY = -1;
\r
6225 case EP_WhiteCannon:
\r
6226 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6227 fromX = fromY = -1;
\r
6230 case EP_WhiteCardinal:
\r
6231 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6232 fromX = fromY = -1;
\r
6235 case EP_WhiteMarshall:
\r
6236 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6237 fromX = fromY = -1;
\r
6240 case EP_WhiteKing:
\r
6241 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6242 fromX = fromY = -1;
\r
6245 case EP_BlackPawn:
\r
6246 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6247 fromX = fromY = -1;
\r
6250 case EP_BlackKnight:
\r
6251 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6252 fromX = fromY = -1;
\r
6255 case EP_BlackBishop:
\r
6256 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6257 fromX = fromY = -1;
\r
6260 case EP_BlackRook:
\r
6261 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6262 fromX = fromY = -1;
\r
6265 case EP_BlackQueen:
\r
6266 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6267 fromX = fromY = -1;
\r
6270 case EP_BlackFerz:
\r
6271 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6272 fromX = fromY = -1;
\r
6275 case EP_BlackWazir:
\r
6276 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6277 fromX = fromY = -1;
\r
6280 case EP_BlackAlfil:
\r
6281 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6282 fromX = fromY = -1;
\r
6285 case EP_BlackCannon:
\r
6286 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6287 fromX = fromY = -1;
\r
6290 case EP_BlackCardinal:
\r
6291 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6292 fromX = fromY = -1;
\r
6295 case EP_BlackMarshall:
\r
6296 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6297 fromX = fromY = -1;
\r
6300 case EP_BlackKing:
\r
6301 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6302 fromX = fromY = -1;
\r
6305 case EP_EmptySquare:
\r
6306 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6307 fromX = fromY = -1;
\r
6310 case EP_ClearBoard:
\r
6311 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6312 fromX = fromY = -1;
\r
6316 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6317 fromX = fromY = -1;
\r
6321 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6322 fromX = fromY = -1;
\r
6326 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6327 fromX = fromY = -1;
\r
6331 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6332 fromX = fromY = -1;
\r
6336 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6337 fromX = fromY = -1;
\r
6341 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6342 fromX = fromY = -1;
\r
6346 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6347 fromX = fromY = -1;
\r
6351 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6352 fromX = fromY = -1;
\r
6356 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6357 fromX = fromY = -1;
\r
6361 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6367 case CLOCK_TIMER_ID:
\r
6368 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6369 clockTimerEvent = 0;
\r
6370 DecrementClocks(); /* call into back end */
\r
6372 case LOAD_GAME_TIMER_ID:
\r
6373 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6374 loadGameTimerEvent = 0;
\r
6375 AutoPlayGameLoop(); /* call into back end */
\r
6377 case ANALYSIS_TIMER_ID:
\r
6378 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6379 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6380 AnalysisPeriodicEvent(0);
\r
6382 KillTimer(hwnd, analysisTimerEvent);
\r
6383 analysisTimerEvent = 0;
\r
6386 case DELAYED_TIMER_ID:
\r
6387 KillTimer(hwnd, delayedTimerEvent);
\r
6388 delayedTimerEvent = 0;
\r
6389 delayedTimerCallback();
\r
6394 case WM_USER_Input:
\r
6395 InputEvent(hwnd, message, wParam, lParam);
\r
6398 /* [AS] Also move "attached" child windows */
\r
6399 case WM_WINDOWPOSCHANGING:
\r
6401 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6402 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6404 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6405 /* Window is moving */
\r
6408 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6409 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6410 rcMain.right = boardX + winWidth;
\r
6411 rcMain.top = boardY;
\r
6412 rcMain.bottom = boardY + winHeight;
\r
6414 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6415 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6416 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6417 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6418 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6425 /* [AS] Snapping */
\r
6426 case WM_ENTERSIZEMOVE:
\r
6427 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6428 if (hwnd == hwndMain) {
\r
6429 doingSizing = TRUE;
\r
6432 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6436 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6437 if (hwnd == hwndMain) {
\r
6438 lastSizing = wParam;
\r
6443 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6444 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6446 case WM_EXITSIZEMOVE:
\r
6447 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6448 if (hwnd == hwndMain) {
\r
6450 doingSizing = FALSE;
\r
6451 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6452 GetClientRect(hwnd, &client);
\r
6453 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6455 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6457 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6460 case WM_DESTROY: /* message: window being destroyed */
\r
6461 PostQuitMessage(0);
\r
6465 if (hwnd == hwndMain) {
\r
6470 default: /* Passes it on if unprocessed */
\r
6471 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6476 /*---------------------------------------------------------------------------*\
\r
6478 * Misc utility routines
\r
6480 \*---------------------------------------------------------------------------*/
\r
6483 * Decent random number generator, at least not as bad as Windows
\r
6484 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6486 unsigned int randstate;
\r
6491 randstate = randstate * 1664525 + 1013904223;
\r
6492 return (int) randstate & 0x7fffffff;
\r
6496 mysrandom(unsigned int seed)
\r
6503 * returns TRUE if user selects a different color, FALSE otherwise
\r
6507 ChangeColor(HWND hwnd, COLORREF *which)
\r
6509 static BOOL firstTime = TRUE;
\r
6510 static DWORD customColors[16];
\r
6512 COLORREF newcolor;
\r
6517 /* Make initial colors in use available as custom colors */
\r
6518 /* Should we put the compiled-in defaults here instead? */
\r
6520 customColors[i++] = lightSquareColor & 0xffffff;
\r
6521 customColors[i++] = darkSquareColor & 0xffffff;
\r
6522 customColors[i++] = whitePieceColor & 0xffffff;
\r
6523 customColors[i++] = blackPieceColor & 0xffffff;
\r
6524 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6525 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6527 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6528 customColors[i++] = textAttribs[ccl].color;
\r
6530 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6531 firstTime = FALSE;
\r
6534 cc.lStructSize = sizeof(cc);
\r
6535 cc.hwndOwner = hwnd;
\r
6536 cc.hInstance = NULL;
\r
6537 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6538 cc.lpCustColors = (LPDWORD) customColors;
\r
6539 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6541 if (!ChooseColor(&cc)) return FALSE;
\r
6543 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6544 if (newcolor == *which) return FALSE;
\r
6545 *which = newcolor;
\r
6549 InitDrawingColors();
\r
6550 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6555 MyLoadSound(MySound *ms)
\r
6561 if (ms->data) free(ms->data);
\r
6564 switch (ms->name[0]) {
\r
6570 /* System sound from Control Panel. Don't preload here. */
\r
6574 if (ms->name[1] == NULLCHAR) {
\r
6575 /* "!" alone = silence */
\r
6578 /* Builtin wave resource. Error if not found. */
\r
6579 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6580 if (h == NULL) break;
\r
6581 ms->data = (void *)LoadResource(hInst, h);
\r
6582 if (h == NULL) break;
\r
6587 /* .wav file. Error if not found. */
\r
6588 f = fopen(ms->name, "rb");
\r
6589 if (f == NULL) break;
\r
6590 if (fstat(fileno(f), &st) < 0) break;
\r
6591 ms->data = malloc(st.st_size);
\r
6592 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6598 char buf[MSG_SIZ];
\r
6599 sprintf(buf, "Error loading sound %s", ms->name);
\r
6600 DisplayError(buf, GetLastError());
\r
6606 MyPlaySound(MySound *ms)
\r
6608 BOOLEAN ok = FALSE;
\r
6610 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6611 switch (ms->name[0]) {
\r
6613 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6618 /* System sound from Control Panel (deprecated feature).
\r
6619 "$" alone or an unset sound name gets default beep (still in use). */
\r
6620 if (ms->name[1]) {
\r
6621 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6623 if (!ok) ok = MessageBeep(MB_OK);
\r
6626 /* Builtin wave resource, or "!" alone for silence */
\r
6627 if (ms->name[1]) {
\r
6628 if (ms->data == NULL) return FALSE;
\r
6629 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6635 /* .wav file. Error if not found. */
\r
6636 if (ms->data == NULL) return FALSE;
\r
6637 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6640 /* Don't print an error: this can happen innocently if the sound driver
\r
6641 is busy; for instance, if another instance of WinBoard is playing
\r
6642 a sound at about the same time. */
\r
6648 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6651 OPENFILENAME *ofn;
\r
6652 static UINT *number; /* gross that this is static */
\r
6654 switch (message) {
\r
6655 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6656 /* Center the dialog over the application window */
\r
6657 ofn = (OPENFILENAME *) lParam;
\r
6658 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6659 number = (UINT *) ofn->lCustData;
\r
6660 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6664 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6665 return FALSE; /* Allow for further processing */
\r
6668 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6669 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6671 return FALSE; /* Allow for further processing */
\r
6677 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6679 static UINT *number;
\r
6680 OPENFILENAME *ofname;
\r
6683 case WM_INITDIALOG:
\r
6684 ofname = (OPENFILENAME *)lParam;
\r
6685 number = (UINT *)(ofname->lCustData);
\r
6688 ofnot = (OFNOTIFY *)lParam;
\r
6689 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6690 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6699 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6700 char *nameFilt, char *dlgTitle, UINT *number,
\r
6701 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6703 OPENFILENAME openFileName;
\r
6704 char buf1[MSG_SIZ];
\r
6707 if (fileName == NULL) fileName = buf1;
\r
6708 if (defName == NULL) {
\r
6709 strcpy(fileName, "*.");
\r
6710 strcat(fileName, defExt);
\r
6712 strcpy(fileName, defName);
\r
6714 if (fileTitle) strcpy(fileTitle, "");
\r
6715 if (number) *number = 0;
\r
6717 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6718 openFileName.hwndOwner = hwnd;
\r
6719 openFileName.hInstance = (HANDLE) hInst;
\r
6720 openFileName.lpstrFilter = nameFilt;
\r
6721 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6722 openFileName.nMaxCustFilter = 0L;
\r
6723 openFileName.nFilterIndex = 1L;
\r
6724 openFileName.lpstrFile = fileName;
\r
6725 openFileName.nMaxFile = MSG_SIZ;
\r
6726 openFileName.lpstrFileTitle = fileTitle;
\r
6727 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6728 openFileName.lpstrInitialDir = NULL;
\r
6729 openFileName.lpstrTitle = dlgTitle;
\r
6730 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6731 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6732 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6733 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6734 openFileName.nFileOffset = 0;
\r
6735 openFileName.nFileExtension = 0;
\r
6736 openFileName.lpstrDefExt = defExt;
\r
6737 openFileName.lCustData = (LONG) number;
\r
6738 openFileName.lpfnHook = oldDialog ?
\r
6739 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6740 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6742 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6743 GetOpenFileName(&openFileName)) {
\r
6744 /* open the file */
\r
6745 f = fopen(openFileName.lpstrFile, write);
\r
6747 MessageBox(hwnd, "File open failed", NULL,
\r
6748 MB_OK|MB_ICONEXCLAMATION);
\r
6752 int err = CommDlgExtendedError();
\r
6753 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6762 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6764 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6767 * Get the first pop-up menu in the menu template. This is the
\r
6768 * menu that TrackPopupMenu displays.
\r
6770 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6772 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6775 * TrackPopup uses screen coordinates, so convert the
\r
6776 * coordinates of the mouse click to screen coordinates.
\r
6778 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6780 /* Draw and track the floating pop-up menu. */
\r
6781 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6782 pt.x, pt.y, 0, hwnd, NULL);
\r
6784 /* Destroy the menu.*/
\r
6785 DestroyMenu(hmenu);
\r
6790 int sizeX, sizeY, newSizeX, newSizeY;
\r
6792 } ResizeEditPlusButtonsClosure;
\r
6795 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6797 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6801 if (hChild == cl->hText) return TRUE;
\r
6802 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6803 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6804 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6805 ScreenToClient(cl->hDlg, &pt);
\r
6806 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6807 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6811 /* Resize a dialog that has a (rich) edit field filling most of
\r
6812 the top, with a row of buttons below */
\r
6814 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6817 int newTextHeight, newTextWidth;
\r
6818 ResizeEditPlusButtonsClosure cl;
\r
6820 /*if (IsIconic(hDlg)) return;*/
\r
6821 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6823 cl.hdwp = BeginDeferWindowPos(8);
\r
6825 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6826 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6827 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6828 if (newTextHeight < 0) {
\r
6829 newSizeY += -newTextHeight;
\r
6830 newTextHeight = 0;
\r
6832 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6833 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6839 cl.newSizeX = newSizeX;
\r
6840 cl.newSizeY = newSizeY;
\r
6841 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6843 EndDeferWindowPos(cl.hdwp);
\r
6846 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6848 RECT rChild, rParent;
\r
6849 int wChild, hChild, wParent, hParent;
\r
6850 int wScreen, hScreen, xNew, yNew;
\r
6853 /* Get the Height and Width of the child window */
\r
6854 GetWindowRect (hwndChild, &rChild);
\r
6855 wChild = rChild.right - rChild.left;
\r
6856 hChild = rChild.bottom - rChild.top;
\r
6858 /* Get the Height and Width of the parent window */
\r
6859 GetWindowRect (hwndParent, &rParent);
\r
6860 wParent = rParent.right - rParent.left;
\r
6861 hParent = rParent.bottom - rParent.top;
\r
6863 /* Get the display limits */
\r
6864 hdc = GetDC (hwndChild);
\r
6865 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6866 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6867 ReleaseDC(hwndChild, hdc);
\r
6869 /* Calculate new X position, then adjust for screen */
\r
6870 xNew = rParent.left + ((wParent - wChild) /2);
\r
6873 } else if ((xNew+wChild) > wScreen) {
\r
6874 xNew = wScreen - wChild;
\r
6877 /* Calculate new Y position, then adjust for screen */
\r
6879 yNew = rParent.top + ((hParent - hChild) /2);
\r
6882 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6887 } else if ((yNew+hChild) > hScreen) {
\r
6888 yNew = hScreen - hChild;
\r
6891 /* Set it, and return */
\r
6892 return SetWindowPos (hwndChild, NULL,
\r
6893 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6896 /* Center one window over another */
\r
6897 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6899 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6902 /*---------------------------------------------------------------------------*\
\r
6904 * Startup Dialog functions
\r
6906 \*---------------------------------------------------------------------------*/
\r
6908 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6910 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6912 while (*cd != NULL) {
\r
6913 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6919 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6921 char buf1[ARG_MAX];
\r
6924 if (str[0] == '@') {
\r
6925 FILE* f = fopen(str + 1, "r");
\r
6927 DisplayFatalError(str + 1, errno, 2);
\r
6930 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6932 buf1[len] = NULLCHAR;
\r
6936 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6939 char buf[MSG_SIZ];
\r
6940 char *end = strchr(str, '\n');
\r
6941 if (end == NULL) return;
\r
6942 memcpy(buf, str, end - str);
\r
6943 buf[end - str] = NULLCHAR;
\r
6944 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6950 SetStartupDialogEnables(HWND hDlg)
\r
6952 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6953 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6954 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6955 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6956 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6957 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6958 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6959 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6960 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6961 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6962 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6963 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6964 IsDlgButtonChecked(hDlg, OPT_View));
\r
6968 QuoteForFilename(char *filename)
\r
6970 int dquote, space;
\r
6971 dquote = strchr(filename, '"') != NULL;
\r
6972 space = strchr(filename, ' ') != NULL;
\r
6973 if (dquote || space) {
\r
6985 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6987 char buf[MSG_SIZ];
\r
6990 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6991 q = QuoteForFilename(nthcp);
\r
6992 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6993 if (*nthdir != NULLCHAR) {
\r
6994 q = QuoteForFilename(nthdir);
\r
6995 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6997 if (*nthcp == NULLCHAR) {
\r
6998 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6999 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7000 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7001 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7006 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7008 char buf[MSG_SIZ];
\r
7012 switch (message) {
\r
7013 case WM_INITDIALOG:
\r
7014 /* Center the dialog */
\r
7015 CenterWindow (hDlg, GetDesktopWindow());
\r
7016 /* Initialize the dialog items */
\r
7017 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7018 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7019 firstChessProgramNames);
\r
7020 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7021 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7022 secondChessProgramNames);
\r
7023 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7024 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7025 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7026 if (*appData.icsHelper != NULLCHAR) {
\r
7027 char *q = QuoteForFilename(appData.icsHelper);
\r
7028 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7030 if (*appData.icsHost == NULLCHAR) {
\r
7031 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7032 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7033 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7034 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7035 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7038 if (appData.icsActive) {
\r
7039 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7041 else if (appData.noChessProgram) {
\r
7042 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7045 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7048 SetStartupDialogEnables(hDlg);
\r
7052 switch (LOWORD(wParam)) {
\r
7054 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7055 strcpy(buf, "/fcp=");
\r
7056 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7058 ParseArgs(StringGet, &p);
\r
7059 strcpy(buf, "/scp=");
\r
7060 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7062 ParseArgs(StringGet, &p);
\r
7063 appData.noChessProgram = FALSE;
\r
7064 appData.icsActive = FALSE;
\r
7065 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7066 strcpy(buf, "/ics /icshost=");
\r
7067 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7069 ParseArgs(StringGet, &p);
\r
7070 if (appData.zippyPlay) {
\r
7071 strcpy(buf, "/fcp=");
\r
7072 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7074 ParseArgs(StringGet, &p);
\r
7076 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7077 appData.noChessProgram = TRUE;
\r
7078 appData.icsActive = FALSE;
\r
7080 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7081 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7084 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7085 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7087 ParseArgs(StringGet, &p);
\r
7089 EndDialog(hDlg, TRUE);
\r
7096 case IDM_HELPCONTENTS:
\r
7097 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7098 MessageBox (GetFocus(),
\r
7099 "Unable to activate help",
\r
7100 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7105 SetStartupDialogEnables(hDlg);
\r
7113 /*---------------------------------------------------------------------------*\
\r
7115 * About box dialog functions
\r
7117 \*---------------------------------------------------------------------------*/
\r
7119 /* Process messages for "About" dialog box */
\r
7121 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7123 switch (message) {
\r
7124 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7125 /* Center the dialog over the application window */
\r
7126 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7127 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7131 case WM_COMMAND: /* message: received a command */
\r
7132 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7133 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7134 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7142 /*---------------------------------------------------------------------------*\
\r
7144 * Comment Dialog functions
\r
7146 \*---------------------------------------------------------------------------*/
\r
7149 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7151 static HANDLE hwndText = NULL;
\r
7152 int len, newSizeX, newSizeY, flags;
\r
7153 static int sizeX, sizeY;
\r
7158 switch (message) {
\r
7159 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7160 /* Initialize the dialog items */
\r
7161 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7162 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7163 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7164 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7165 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7166 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7167 SetWindowText(hDlg, commentTitle);
\r
7168 if (editComment) {
\r
7169 SetFocus(hwndText);
\r
7171 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7173 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7174 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7175 MAKELPARAM(FALSE, 0));
\r
7176 /* Size and position the dialog */
\r
7177 if (!commentDialog) {
\r
7178 commentDialog = hDlg;
\r
7179 flags = SWP_NOZORDER;
\r
7180 GetClientRect(hDlg, &rect);
\r
7181 sizeX = rect.right;
\r
7182 sizeY = rect.bottom;
\r
7183 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7184 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7185 WINDOWPLACEMENT wp;
\r
7186 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7187 wp.length = sizeof(WINDOWPLACEMENT);
\r
7189 wp.showCmd = SW_SHOW;
\r
7190 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7191 wp.rcNormalPosition.left = commentX;
\r
7192 wp.rcNormalPosition.right = commentX + commentW;
\r
7193 wp.rcNormalPosition.top = commentY;
\r
7194 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7195 SetWindowPlacement(hDlg, &wp);
\r
7197 GetClientRect(hDlg, &rect);
\r
7198 newSizeX = rect.right;
\r
7199 newSizeY = rect.bottom;
\r
7200 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7201 newSizeX, newSizeY);
\r
7208 case WM_COMMAND: /* message: received a command */
\r
7209 switch (LOWORD(wParam)) {
\r
7211 if (editComment) {
\r
7213 /* Read changed options from the dialog box */
\r
7214 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7215 len = GetWindowTextLength(hwndText);
\r
7216 str = (char *) malloc(len + 1);
\r
7217 GetWindowText(hwndText, str, len + 1);
\r
7226 ReplaceComment(commentIndex, str);
\r
7233 case OPT_CancelComment:
\r
7237 case OPT_ClearComment:
\r
7238 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7241 case OPT_EditComment:
\r
7242 EditCommentEvent();
\r
7251 newSizeX = LOWORD(lParam);
\r
7252 newSizeY = HIWORD(lParam);
\r
7253 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7258 case WM_GETMINMAXINFO:
\r
7259 /* Prevent resizing window too small */
\r
7260 mmi = (MINMAXINFO *) lParam;
\r
7261 mmi->ptMinTrackSize.x = 100;
\r
7262 mmi->ptMinTrackSize.y = 100;
\r
7269 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7274 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7276 if (str == NULL) str = "";
\r
7277 p = (char *) malloc(2 * strlen(str) + 2);
\r
7280 if (*str == '\n') *q++ = '\r';
\r
7284 if (commentText != NULL) free(commentText);
\r
7286 commentIndex = index;
\r
7287 commentTitle = title;
\r
7289 editComment = edit;
\r
7291 if (commentDialog) {
\r
7292 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7293 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7295 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7296 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7297 hwndMain, (DLGPROC)lpProc);
\r
7298 FreeProcInstance(lpProc);
\r
7300 commentDialogUp = TRUE;
\r
7304 /*---------------------------------------------------------------------------*\
\r
7306 * Type-in move dialog functions
\r
7308 \*---------------------------------------------------------------------------*/
\r
7311 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7313 char move[MSG_SIZ];
\r
7315 ChessMove moveType;
\r
7316 int fromX, fromY, toX, toY;
\r
7319 switch (message) {
\r
7320 case WM_INITDIALOG:
\r
7321 move[0] = (char) lParam;
\r
7322 move[1] = NULLCHAR;
\r
7323 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7324 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7325 SetWindowText(hInput, move);
\r
7327 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7331 switch (LOWORD(wParam)) {
\r
7333 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7334 { int n; Board board;
\r
7336 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7337 EditPositionPasteFEN(move);
\r
7338 EndDialog(hDlg, TRUE);
\r
7341 // [HGM] movenum: allow move number to be typed in any mode
\r
7342 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7343 currentMove = 2*n-1;
\r
7344 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7345 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7346 EndDialog(hDlg, TRUE);
\r
7347 DrawPosition(TRUE, boards[currentMove]);
\r
7348 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7349 else DisplayMessage("", "");
\r
7353 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7354 gameMode != Training) {
\r
7355 DisplayMoveError("Displayed move is not current");
\r
7357 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7358 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7359 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7360 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7361 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7362 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7363 if (gameMode != Training)
\r
7364 forwardMostMove = currentMove;
\r
7365 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7367 DisplayMoveError("Could not parse move");
\r
7370 EndDialog(hDlg, TRUE);
\r
7373 EndDialog(hDlg, FALSE);
\r
7384 PopUpMoveDialog(char firstchar)
\r
7388 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7389 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7390 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7391 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7392 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7393 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7394 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7395 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7396 gameMode == Training) {
\r
7397 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7398 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7399 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7400 FreeProcInstance(lpProc);
\r
7404 /*---------------------------------------------------------------------------*\
\r
7406 * Type-in name dialog functions
\r
7408 \*---------------------------------------------------------------------------*/
\r
7411 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7413 char move[MSG_SIZ];
\r
7416 switch (message) {
\r
7417 case WM_INITDIALOG:
\r
7418 move[0] = (char) lParam;
\r
7419 move[1] = NULLCHAR;
\r
7420 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7421 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7422 SetWindowText(hInput, move);
\r
7424 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7428 switch (LOWORD(wParam)) {
\r
7430 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7431 appData.userName = strdup(move);
\r
7434 EndDialog(hDlg, TRUE);
\r
7437 EndDialog(hDlg, FALSE);
\r
7448 PopUpNameDialog(char firstchar)
\r
7452 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7453 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7454 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7455 FreeProcInstance(lpProc);
\r
7458 /*---------------------------------------------------------------------------*\
\r
7462 \*---------------------------------------------------------------------------*/
\r
7464 /* Nonmodal error box */
\r
7465 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7466 WPARAM wParam, LPARAM lParam);
\r
7469 ErrorPopUp(char *title, char *content)
\r
7473 BOOLEAN modal = hwndMain == NULL;
\r
7491 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7492 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7495 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7497 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7498 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7499 hwndMain, (DLGPROC)lpProc);
\r
7500 FreeProcInstance(lpProc);
\r
7507 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7508 if (errorDialog == NULL) return;
\r
7509 DestroyWindow(errorDialog);
\r
7510 errorDialog = NULL;
\r
7514 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7519 switch (message) {
\r
7520 case WM_INITDIALOG:
\r
7521 GetWindowRect(hDlg, &rChild);
\r
7524 SetWindowPos(hDlg, NULL, rChild.left,
\r
7525 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7526 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7530 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7531 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7532 and it doesn't work when you resize the dialog.
\r
7533 For now, just give it a default position.
\r
7535 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7537 errorDialog = hDlg;
\r
7538 SetWindowText(hDlg, errorTitle);
\r
7539 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7540 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7544 switch (LOWORD(wParam)) {
\r
7547 if (errorDialog == hDlg) errorDialog = NULL;
\r
7548 DestroyWindow(hDlg);
\r
7560 HWND gothicDialog = NULL;
\r
7563 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7567 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7569 switch (message) {
\r
7570 case WM_INITDIALOG:
\r
7571 GetWindowRect(hDlg, &rChild);
\r
7573 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7577 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7578 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7579 and it doesn't work when you resize the dialog.
\r
7580 For now, just give it a default position.
\r
7582 gothicDialog = hDlg;
\r
7583 SetWindowText(hDlg, errorTitle);
\r
7584 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7585 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7589 switch (LOWORD(wParam)) {
\r
7592 if (errorDialog == hDlg) errorDialog = NULL;
\r
7593 DestroyWindow(hDlg);
\r
7605 GothicPopUp(char *title, VariantClass variant)
\r
7608 static char *lastTitle;
\r
7610 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7611 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7613 if(lastTitle != title && gothicDialog != NULL) {
\r
7614 DestroyWindow(gothicDialog);
\r
7615 gothicDialog = NULL;
\r
7617 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7618 title = lastTitle;
\r
7619 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7620 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7621 hwndMain, (DLGPROC)lpProc);
\r
7622 FreeProcInstance(lpProc);
\r
7627 /*---------------------------------------------------------------------------*\
\r
7629 * Ics Interaction console functions
\r
7631 \*---------------------------------------------------------------------------*/
\r
7633 #define HISTORY_SIZE 64
\r
7634 static char *history[HISTORY_SIZE];
\r
7635 int histIn = 0, histP = 0;
\r
7638 SaveInHistory(char *cmd)
\r
7640 if (history[histIn] != NULL) {
\r
7641 free(history[histIn]);
\r
7642 history[histIn] = NULL;
\r
7644 if (*cmd == NULLCHAR) return;
\r
7645 history[histIn] = StrSave(cmd);
\r
7646 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7647 if (history[histIn] != NULL) {
\r
7648 free(history[histIn]);
\r
7649 history[histIn] = NULL;
\r
7655 PrevInHistory(char *cmd)
\r
7658 if (histP == histIn) {
\r
7659 if (history[histIn] != NULL) free(history[histIn]);
\r
7660 history[histIn] = StrSave(cmd);
\r
7662 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7663 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7665 return history[histP];
\r
7671 if (histP == histIn) return NULL;
\r
7672 histP = (histP + 1) % HISTORY_SIZE;
\r
7673 return history[histP];
\r
7680 BOOLEAN immediate;
\r
7681 } IcsTextMenuEntry;
\r
7682 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7683 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7686 ParseIcsTextMenu(char *icsTextMenuString)
\r
7689 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7690 char *p = icsTextMenuString;
\r
7691 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7694 if (e->command != NULL) {
\r
7696 e->command = NULL;
\r
7700 e = icsTextMenuEntry;
\r
7701 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7702 if (*p == ';' || *p == '\n') {
\r
7703 e->item = strdup("-");
\r
7704 e->command = NULL;
\r
7706 } else if (*p == '-') {
\r
7707 e->item = strdup("-");
\r
7708 e->command = NULL;
\r
7712 char *q, *r, *s, *t;
\r
7714 q = strchr(p, ',');
\r
7715 if (q == NULL) break;
\r
7717 r = strchr(q + 1, ',');
\r
7718 if (r == NULL) break;
\r
7720 s = strchr(r + 1, ',');
\r
7721 if (s == NULL) break;
\r
7724 t = strchr(s + 1, c);
\r
7727 t = strchr(s + 1, c);
\r
7729 if (t != NULL) *t = NULLCHAR;
\r
7730 e->item = strdup(p);
\r
7731 e->command = strdup(q + 1);
\r
7732 e->getname = *(r + 1) != '0';
\r
7733 e->immediate = *(s + 1) != '0';
\r
7737 if (t == NULL) break;
\r
7746 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7750 hmenu = LoadMenu(hInst, "TextMenu");
\r
7751 h = GetSubMenu(hmenu, 0);
\r
7753 if (strcmp(e->item, "-") == 0) {
\r
7754 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7756 if (e->item[0] == '|') {
\r
7757 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7758 IDM_CommandX + i, &e->item[1]);
\r
7760 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7769 WNDPROC consoleTextWindowProc;
\r
7772 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7774 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7775 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7779 SetWindowText(hInput, command);
\r
7781 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7783 sel.cpMin = 999999;
\r
7784 sel.cpMax = 999999;
\r
7785 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7790 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7791 if (sel.cpMin == sel.cpMax) {
\r
7792 /* Expand to surrounding word */
\r
7795 tr.chrg.cpMax = sel.cpMin;
\r
7796 tr.chrg.cpMin = --sel.cpMin;
\r
7797 if (sel.cpMin < 0) break;
\r
7798 tr.lpstrText = name;
\r
7799 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7800 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7804 tr.chrg.cpMin = sel.cpMax;
\r
7805 tr.chrg.cpMax = ++sel.cpMax;
\r
7806 tr.lpstrText = name;
\r
7807 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7808 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7811 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7812 MessageBeep(MB_ICONEXCLAMATION);
\r
7816 tr.lpstrText = name;
\r
7817 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7819 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7820 MessageBeep(MB_ICONEXCLAMATION);
\r
7823 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7826 sprintf(buf, "%s %s", command, name);
\r
7827 SetWindowText(hInput, buf);
\r
7828 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7830 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7831 SetWindowText(hInput, buf);
\r
7832 sel.cpMin = 999999;
\r
7833 sel.cpMax = 999999;
\r
7834 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7840 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7845 switch (message) {
\r
7847 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7850 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7853 sel.cpMin = 999999;
\r
7854 sel.cpMax = 999999;
\r
7855 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7856 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7861 if(wParam != '\022') {
\r
7862 if (wParam == '\t') {
\r
7863 if (GetKeyState(VK_SHIFT) < 0) {
\r
7865 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7866 if (buttonDesc[0].hwnd) {
\r
7867 SetFocus(buttonDesc[0].hwnd);
\r
7869 SetFocus(hwndMain);
\r
7873 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7876 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7877 JAWS_DELETE( SetFocus(hInput); )
\r
7878 SendMessage(hInput, message, wParam, lParam);
\r
7881 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7882 case WM_RBUTTONUP:
\r
7883 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7884 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7885 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7888 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7889 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7890 if (sel.cpMin == sel.cpMax) {
\r
7891 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7892 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7894 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7895 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7897 pt.x = LOWORD(lParam);
\r
7898 pt.y = HIWORD(lParam);
\r
7899 MenuPopup(hwnd, pt, hmenu, -1);
\r
7903 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7905 return SendMessage(hInput, message, wParam, lParam);
\r
7906 case WM_MBUTTONDOWN:
\r
7907 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7908 case WM_RBUTTONDOWN:
\r
7909 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7910 /* Move selection here if it was empty */
\r
7912 pt.x = LOWORD(lParam);
\r
7913 pt.y = HIWORD(lParam);
\r
7914 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7915 if (sel.cpMin == sel.cpMax) {
\r
7916 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7917 sel.cpMax = sel.cpMin;
\r
7918 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7920 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7924 switch (LOWORD(wParam)) {
\r
7925 case IDM_QuickPaste:
\r
7927 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7928 if (sel.cpMin == sel.cpMax) {
\r
7929 MessageBeep(MB_ICONEXCLAMATION);
\r
7932 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7933 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7934 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7939 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7942 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7945 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7949 int i = LOWORD(wParam) - IDM_CommandX;
\r
7950 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7951 icsTextMenuEntry[i].command != NULL) {
\r
7952 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7953 icsTextMenuEntry[i].getname,
\r
7954 icsTextMenuEntry[i].immediate);
\r
7962 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7965 WNDPROC consoleInputWindowProc;
\r
7968 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7970 char buf[MSG_SIZ];
\r
7972 static BOOL sendNextChar = FALSE;
\r
7973 static BOOL quoteNextChar = FALSE;
\r
7974 InputSource *is = consoleInputSource;
\r
7978 switch (message) {
\r
7980 if (!appData.localLineEditing || sendNextChar) {
\r
7981 is->buf[0] = (CHAR) wParam;
\r
7983 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7984 sendNextChar = FALSE;
\r
7987 if (quoteNextChar) {
\r
7988 buf[0] = (char) wParam;
\r
7989 buf[1] = NULLCHAR;
\r
7990 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7991 quoteNextChar = FALSE;
\r
7995 case '\r': /* Enter key */
\r
7996 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7997 if (consoleEcho) SaveInHistory(is->buf);
\r
7998 is->buf[is->count++] = '\n';
\r
7999 is->buf[is->count] = NULLCHAR;
\r
8000 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8001 if (consoleEcho) {
\r
8002 ConsoleOutput(is->buf, is->count, TRUE);
\r
8003 } else if (appData.localLineEditing) {
\r
8004 ConsoleOutput("\n", 1, TRUE);
\r
8007 case '\033': /* Escape key */
\r
8008 SetWindowText(hwnd, "");
\r
8009 cf.cbSize = sizeof(CHARFORMAT);
\r
8010 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8011 if (consoleEcho) {
\r
8012 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8014 cf.crTextColor = COLOR_ECHOOFF;
\r
8016 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8017 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8019 case '\t': /* Tab key */
\r
8020 if (GetKeyState(VK_SHIFT) < 0) {
\r
8022 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8025 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8026 if (buttonDesc[0].hwnd) {
\r
8027 SetFocus(buttonDesc[0].hwnd);
\r
8029 SetFocus(hwndMain);
\r
8033 case '\023': /* Ctrl+S */
\r
8034 sendNextChar = TRUE;
\r
8036 case '\021': /* Ctrl+Q */
\r
8037 quoteNextChar = TRUE;
\r
8047 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8048 p = PrevInHistory(buf);
\r
8050 SetWindowText(hwnd, p);
\r
8051 sel.cpMin = 999999;
\r
8052 sel.cpMax = 999999;
\r
8053 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8058 p = NextInHistory();
\r
8060 SetWindowText(hwnd, p);
\r
8061 sel.cpMin = 999999;
\r
8062 sel.cpMax = 999999;
\r
8063 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8069 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8073 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8077 case WM_MBUTTONDOWN:
\r
8078 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8079 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8081 case WM_RBUTTONUP:
\r
8082 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8083 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8084 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8088 hmenu = LoadMenu(hInst, "InputMenu");
\r
8089 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8090 if (sel.cpMin == sel.cpMax) {
\r
8091 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8092 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8094 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8095 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8097 pt.x = LOWORD(lParam);
\r
8098 pt.y = HIWORD(lParam);
\r
8099 MenuPopup(hwnd, pt, hmenu, -1);
\r
8103 switch (LOWORD(wParam)) {
\r
8105 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8107 case IDM_SelectAll:
\r
8109 sel.cpMax = -1; /*999999?*/
\r
8110 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8113 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8116 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8119 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8124 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8127 #define CO_MAX 100000
\r
8128 #define CO_TRIM 1000
\r
8131 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8133 static SnapData sd;
\r
8134 HWND hText, hInput;
\r
8136 static int sizeX, sizeY;
\r
8137 int newSizeX, newSizeY;
\r
8141 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8142 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8144 switch (message) {
\r
8146 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8148 ENLINK *pLink = (ENLINK*)lParam;
\r
8149 if (pLink->msg == WM_LBUTTONUP)
\r
8153 tr.chrg = pLink->chrg;
\r
8154 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8155 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8156 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8157 free(tr.lpstrText);
\r
8161 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8162 hwndConsole = hDlg;
\r
8164 consoleTextWindowProc = (WNDPROC)
\r
8165 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8166 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8167 consoleInputWindowProc = (WNDPROC)
\r
8168 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8169 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8170 Colorize(ColorNormal, TRUE);
\r
8171 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8172 ChangedConsoleFont();
\r
8173 GetClientRect(hDlg, &rect);
\r
8174 sizeX = rect.right;
\r
8175 sizeY = rect.bottom;
\r
8176 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8177 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8178 WINDOWPLACEMENT wp;
\r
8179 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8180 wp.length = sizeof(WINDOWPLACEMENT);
\r
8182 wp.showCmd = SW_SHOW;
\r
8183 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8184 wp.rcNormalPosition.left = wpConsole.x;
\r
8185 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8186 wp.rcNormalPosition.top = wpConsole.y;
\r
8187 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8188 SetWindowPlacement(hDlg, &wp);
\r
8191 // [HGM] Chessknight's change 2004-07-13
\r
8192 else { /* Determine Defaults */
\r
8193 WINDOWPLACEMENT wp;
\r
8194 wpConsole.x = winWidth + 1;
\r
8195 wpConsole.y = boardY;
\r
8196 wpConsole.width = screenWidth - winWidth;
\r
8197 wpConsole.height = winHeight;
\r
8198 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8199 wp.length = sizeof(WINDOWPLACEMENT);
\r
8201 wp.showCmd = SW_SHOW;
\r
8202 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8203 wp.rcNormalPosition.left = wpConsole.x;
\r
8204 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8205 wp.rcNormalPosition.top = wpConsole.y;
\r
8206 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8207 SetWindowPlacement(hDlg, &wp);
\r
8210 // Allow hText to highlight URLs and send notifications on them
\r
8211 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8212 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8213 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8214 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8228 if (IsIconic(hDlg)) break;
\r
8229 newSizeX = LOWORD(lParam);
\r
8230 newSizeY = HIWORD(lParam);
\r
8231 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8232 RECT rectText, rectInput;
\r
8234 int newTextHeight, newTextWidth;
\r
8235 GetWindowRect(hText, &rectText);
\r
8236 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8237 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8238 if (newTextHeight < 0) {
\r
8239 newSizeY += -newTextHeight;
\r
8240 newTextHeight = 0;
\r
8242 SetWindowPos(hText, NULL, 0, 0,
\r
8243 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8244 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8245 pt.x = rectInput.left;
\r
8246 pt.y = rectInput.top + newSizeY - sizeY;
\r
8247 ScreenToClient(hDlg, &pt);
\r
8248 SetWindowPos(hInput, NULL,
\r
8249 pt.x, pt.y, /* needs client coords */
\r
8250 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8251 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8257 case WM_GETMINMAXINFO:
\r
8258 /* Prevent resizing window too small */
\r
8259 mmi = (MINMAXINFO *) lParam;
\r
8260 mmi->ptMinTrackSize.x = 100;
\r
8261 mmi->ptMinTrackSize.y = 100;
\r
8264 /* [AS] Snapping */
\r
8265 case WM_ENTERSIZEMOVE:
\r
8266 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8269 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8272 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8274 case WM_EXITSIZEMOVE:
\r
8275 UpdateICSWidth(hText);
\r
8276 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8279 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8287 if (hwndConsole) return;
\r
8288 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8289 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8294 ConsoleOutput(char* data, int length, int forceVisible)
\r
8299 char buf[CO_MAX+1];
\r
8302 static int delayLF = 0;
\r
8303 CHARRANGE savesel, sel;
\r
8305 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8313 while (length--) {
\r
8321 } else if (*p == '\007') {
\r
8322 MyPlaySound(&sounds[(int)SoundBell]);
\r
8329 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8330 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8331 /* Save current selection */
\r
8332 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8333 exlen = GetWindowTextLength(hText);
\r
8334 /* Find out whether current end of text is visible */
\r
8335 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8336 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8337 /* Trim existing text if it's too long */
\r
8338 if (exlen + (q - buf) > CO_MAX) {
\r
8339 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8342 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8343 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8345 savesel.cpMin -= trim;
\r
8346 savesel.cpMax -= trim;
\r
8347 if (exlen < 0) exlen = 0;
\r
8348 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8349 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8351 /* Append the new text */
\r
8352 sel.cpMin = exlen;
\r
8353 sel.cpMax = exlen;
\r
8354 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8355 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8356 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8357 if (forceVisible || exlen == 0 ||
\r
8358 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8359 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8360 /* Scroll to make new end of text visible if old end of text
\r
8361 was visible or new text is an echo of user typein */
\r
8362 sel.cpMin = 9999999;
\r
8363 sel.cpMax = 9999999;
\r
8364 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8365 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8366 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8367 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8369 if (savesel.cpMax == exlen || forceVisible) {
\r
8370 /* Move insert point to new end of text if it was at the old
\r
8371 end of text or if the new text is an echo of user typein */
\r
8372 sel.cpMin = 9999999;
\r
8373 sel.cpMax = 9999999;
\r
8374 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8376 /* Restore previous selection */
\r
8377 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8379 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8386 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8390 COLORREF oldFg, oldBg;
\r
8394 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8396 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8397 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8398 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8401 rect.right = x + squareSize;
\r
8403 rect.bottom = y + squareSize;
\r
8406 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8407 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8408 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8409 &rect, str, strlen(str), NULL);
\r
8411 (void) SetTextColor(hdc, oldFg);
\r
8412 (void) SetBkColor(hdc, oldBg);
\r
8413 (void) SelectObject(hdc, oldFont);
\r
8417 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8418 RECT *rect, char *color, char *flagFell)
\r
8422 COLORREF oldFg, oldBg;
\r
8425 if (appData.clockMode) {
\r
8427 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8429 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8436 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8437 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8439 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8440 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8442 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8446 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8447 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8448 rect, str, strlen(str), NULL);
\r
8449 if(logoHeight > 0 && appData.clockMode) {
\r
8451 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8452 r.top = rect->top + logoHeight/2;
\r
8453 r.left = rect->left;
\r
8454 r.right = rect->right;
\r
8455 r.bottom = rect->bottom;
\r
8456 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8457 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8458 &r, str, strlen(str), NULL);
\r
8460 (void) SetTextColor(hdc, oldFg);
\r
8461 (void) SetBkColor(hdc, oldBg);
\r
8462 (void) SelectObject(hdc, oldFont);
\r
8467 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8473 if( count <= 0 ) {
\r
8474 if (appData.debugMode) {
\r
8475 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8478 return ERROR_INVALID_USER_BUFFER;
\r
8481 ResetEvent(ovl->hEvent);
\r
8482 ovl->Offset = ovl->OffsetHigh = 0;
\r
8483 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8487 err = GetLastError();
\r
8488 if (err == ERROR_IO_PENDING) {
\r
8489 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8493 err = GetLastError();
\r
8500 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8505 ResetEvent(ovl->hEvent);
\r
8506 ovl->Offset = ovl->OffsetHigh = 0;
\r
8507 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8511 err = GetLastError();
\r
8512 if (err == ERROR_IO_PENDING) {
\r
8513 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8517 err = GetLastError();
\r
8523 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8524 void CheckForInputBufferFull( InputSource * is )
\r
8526 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8527 /* Look for end of line */
\r
8528 char * p = is->buf;
\r
8530 while( p < is->next && *p != '\n' ) {
\r
8534 if( p >= is->next ) {
\r
8535 if (appData.debugMode) {
\r
8536 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8539 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8540 is->count = (DWORD) -1;
\r
8541 is->next = is->buf;
\r
8547 InputThread(LPVOID arg)
\r
8552 is = (InputSource *) arg;
\r
8553 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8554 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8555 while (is->hThread != NULL) {
\r
8556 is->error = DoReadFile(is->hFile, is->next,
\r
8557 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8558 &is->count, &ovl);
\r
8559 if (is->error == NO_ERROR) {
\r
8560 is->next += is->count;
\r
8562 if (is->error == ERROR_BROKEN_PIPE) {
\r
8563 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8566 is->count = (DWORD) -1;
\r
8567 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8572 CheckForInputBufferFull( is );
\r
8574 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8576 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8578 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8581 CloseHandle(ovl.hEvent);
\r
8582 CloseHandle(is->hFile);
\r
8584 if (appData.debugMode) {
\r
8585 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8592 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8594 NonOvlInputThread(LPVOID arg)
\r
8601 is = (InputSource *) arg;
\r
8602 while (is->hThread != NULL) {
\r
8603 is->error = ReadFile(is->hFile, is->next,
\r
8604 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8605 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8606 if (is->error == NO_ERROR) {
\r
8607 /* Change CRLF to LF */
\r
8608 if (is->next > is->buf) {
\r
8610 i = is->count + 1;
\r
8618 if (prev == '\r' && *p == '\n') {
\r
8630 if (is->error == ERROR_BROKEN_PIPE) {
\r
8631 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8634 is->count = (DWORD) -1;
\r
8638 CheckForInputBufferFull( is );
\r
8640 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8642 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8644 if (is->count < 0) break; /* Quit on error */
\r
8646 CloseHandle(is->hFile);
\r
8651 SocketInputThread(LPVOID arg)
\r
8655 is = (InputSource *) arg;
\r
8656 while (is->hThread != NULL) {
\r
8657 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8658 if ((int)is->count == SOCKET_ERROR) {
\r
8659 is->count = (DWORD) -1;
\r
8660 is->error = WSAGetLastError();
\r
8662 is->error = NO_ERROR;
\r
8663 is->next += is->count;
\r
8664 if (is->count == 0 && is->second == is) {
\r
8665 /* End of file on stderr; quit with no message */
\r
8669 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8671 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8673 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8679 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8683 is = (InputSource *) lParam;
\r
8684 if (is->lineByLine) {
\r
8685 /* Feed in lines one by one */
\r
8686 char *p = is->buf;
\r
8688 while (q < is->next) {
\r
8689 if (*q++ == '\n') {
\r
8690 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8695 /* Move any partial line to the start of the buffer */
\r
8697 while (p < is->next) {
\r
8702 if (is->error != NO_ERROR || is->count == 0) {
\r
8703 /* Notify backend of the error. Note: If there was a partial
\r
8704 line at the end, it is not flushed through. */
\r
8705 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8708 /* Feed in the whole chunk of input at once */
\r
8709 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8710 is->next = is->buf;
\r
8714 /*---------------------------------------------------------------------------*\
\r
8716 * Menu enables. Used when setting various modes.
\r
8718 \*---------------------------------------------------------------------------*/
\r
8726 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8728 while (enab->item > 0) {
\r
8729 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8734 Enables gnuEnables[] = {
\r
8735 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8736 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8737 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8738 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8739 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8740 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8742 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8744 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8745 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8749 Enables icsEnables[] = {
\r
8750 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8757 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8760 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8761 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8762 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8763 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8764 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8769 Enables zippyEnables[] = {
\r
8770 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8771 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8772 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8773 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8778 Enables ncpEnables[] = {
\r
8779 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8788 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8801 Enables trainingOnEnables[] = {
\r
8802 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8813 Enables trainingOffEnables[] = {
\r
8814 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8815 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8816 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8817 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8819 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8820 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8821 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8825 /* These modify either ncpEnables or gnuEnables */
\r
8826 Enables cmailEnables[] = {
\r
8827 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8828 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8829 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8830 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8832 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8837 Enables machineThinkingEnables[] = {
\r
8838 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8851 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8852 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8856 Enables userThinkingEnables[] = {
\r
8857 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8862 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8863 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8864 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8865 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8866 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8867 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8868 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8869 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8870 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8871 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8875 /*---------------------------------------------------------------------------*\
\r
8877 * Front-end interface functions exported by XBoard.
\r
8878 * Functions appear in same order as prototypes in frontend.h.
\r
8880 \*---------------------------------------------------------------------------*/
\r
8884 static UINT prevChecked = 0;
\r
8885 static int prevPausing = 0;
\r
8888 if (pausing != prevPausing) {
\r
8889 prevPausing = pausing;
\r
8890 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8891 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8892 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8895 switch (gameMode) {
\r
8896 case BeginningOfGame:
\r
8897 if (appData.icsActive)
\r
8898 nowChecked = IDM_IcsClient;
\r
8899 else if (appData.noChessProgram)
\r
8900 nowChecked = IDM_EditGame;
\r
8902 nowChecked = IDM_MachineBlack;
\r
8904 case MachinePlaysBlack:
\r
8905 nowChecked = IDM_MachineBlack;
\r
8907 case MachinePlaysWhite:
\r
8908 nowChecked = IDM_MachineWhite;
\r
8910 case TwoMachinesPlay:
\r
8911 nowChecked = IDM_TwoMachines;
\r
8914 nowChecked = IDM_AnalysisMode;
\r
8917 nowChecked = IDM_AnalyzeFile;
\r
8920 nowChecked = IDM_EditGame;
\r
8922 case PlayFromGameFile:
\r
8923 nowChecked = IDM_LoadGame;
\r
8925 case EditPosition:
\r
8926 nowChecked = IDM_EditPosition;
\r
8929 nowChecked = IDM_Training;
\r
8931 case IcsPlayingWhite:
\r
8932 case IcsPlayingBlack:
\r
8933 case IcsObserving:
\r
8935 nowChecked = IDM_IcsClient;
\r
8942 if (prevChecked != 0)
\r
8943 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8944 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8945 if (nowChecked != 0)
\r
8946 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8947 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8949 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8950 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8951 MF_BYCOMMAND|MF_ENABLED);
\r
8953 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8954 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8957 prevChecked = nowChecked;
\r
8959 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8960 if (appData.icsActive) {
\r
8961 if (appData.icsEngineAnalyze) {
\r
8962 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8963 MF_BYCOMMAND|MF_CHECKED);
\r
8965 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8966 MF_BYCOMMAND|MF_UNCHECKED);
\r
8974 HMENU hmenu = GetMenu(hwndMain);
\r
8975 SetMenuEnables(hmenu, icsEnables);
\r
8976 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8977 MF_BYPOSITION|MF_ENABLED);
\r
8979 if (appData.zippyPlay) {
\r
8980 SetMenuEnables(hmenu, zippyEnables);
\r
8981 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8982 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8983 MF_BYCOMMAND|MF_ENABLED);
\r
8991 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8997 HMENU hmenu = GetMenu(hwndMain);
\r
8998 SetMenuEnables(hmenu, ncpEnables);
\r
8999 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9000 MF_BYPOSITION|MF_GRAYED);
\r
9001 DrawMenuBar(hwndMain);
\r
9007 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9011 SetTrainingModeOn()
\r
9014 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9015 for (i = 0; i < N_BUTTONS; i++) {
\r
9016 if (buttonDesc[i].hwnd != NULL)
\r
9017 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9022 VOID SetTrainingModeOff()
\r
9025 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9026 for (i = 0; i < N_BUTTONS; i++) {
\r
9027 if (buttonDesc[i].hwnd != NULL)
\r
9028 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9034 SetUserThinkingEnables()
\r
9036 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9040 SetMachineThinkingEnables()
\r
9042 HMENU hMenu = GetMenu(hwndMain);
\r
9043 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9045 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9047 if (gameMode == MachinePlaysBlack) {
\r
9048 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9049 } else if (gameMode == MachinePlaysWhite) {
\r
9050 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9051 } else if (gameMode == TwoMachinesPlay) {
\r
9052 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9058 DisplayTitle(char *str)
\r
9060 char title[MSG_SIZ], *host;
\r
9061 if (str[0] != NULLCHAR) {
\r
9062 strcpy(title, str);
\r
9063 } else if (appData.icsActive) {
\r
9064 if (appData.icsCommPort[0] != NULLCHAR)
\r
9067 host = appData.icsHost;
\r
9068 sprintf(title, "%s: %s", szTitle, host);
\r
9069 } else if (appData.noChessProgram) {
\r
9070 strcpy(title, szTitle);
\r
9072 strcpy(title, szTitle);
\r
9073 strcat(title, ": ");
\r
9074 strcat(title, first.tidy);
\r
9076 SetWindowText(hwndMain, title);
\r
9081 DisplayMessage(char *str1, char *str2)
\r
9085 int remain = MESSAGE_TEXT_MAX - 1;
\r
9088 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9089 messageText[0] = NULLCHAR;
\r
9091 len = strlen(str1);
\r
9092 if (len > remain) len = remain;
\r
9093 strncpy(messageText, str1, len);
\r
9094 messageText[len] = NULLCHAR;
\r
9097 if (*str2 && remain >= 2) {
\r
9099 strcat(messageText, " ");
\r
9102 len = strlen(str2);
\r
9103 if (len > remain) len = remain;
\r
9104 strncat(messageText, str2, len);
\r
9106 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9108 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9112 hdc = GetDC(hwndMain);
\r
9113 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9114 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9115 &messageRect, messageText, strlen(messageText), NULL);
\r
9116 (void) SelectObject(hdc, oldFont);
\r
9117 (void) ReleaseDC(hwndMain, hdc);
\r
9121 DisplayError(char *str, int error)
\r
9123 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9129 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9130 NULL, error, LANG_NEUTRAL,
\r
9131 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9133 sprintf(buf, "%s:\n%s", str, buf2);
\r
9135 ErrorMap *em = errmap;
\r
9136 while (em->err != 0 && em->err != error) em++;
\r
9137 if (em->err != 0) {
\r
9138 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9140 sprintf(buf, "%s:\nError code %d", str, error);
\r
9145 ErrorPopUp("Error", buf);
\r
9150 DisplayMoveError(char *str)
\r
9152 fromX = fromY = -1;
\r
9153 ClearHighlights();
\r
9154 DrawPosition(FALSE, NULL);
\r
9155 if (appData.popupMoveErrors) {
\r
9156 ErrorPopUp("Error", str);
\r
9158 DisplayMessage(str, "");
\r
9159 moveErrorMessageUp = TRUE;
\r
9164 DisplayFatalError(char *str, int error, int exitStatus)
\r
9166 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9168 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9171 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9172 NULL, error, LANG_NEUTRAL,
\r
9173 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9175 sprintf(buf, "%s:\n%s", str, buf2);
\r
9177 ErrorMap *em = errmap;
\r
9178 while (em->err != 0 && em->err != error) em++;
\r
9179 if (em->err != 0) {
\r
9180 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9182 sprintf(buf, "%s:\nError code %d", str, error);
\r
9187 if (appData.debugMode) {
\r
9188 fprintf(debugFP, "%s: %s\n", label, str);
\r
9190 if (appData.popupExitMessage) {
\r
9191 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9192 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9194 ExitEvent(exitStatus);
\r
9199 DisplayInformation(char *str)
\r
9201 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9206 DisplayNote(char *str)
\r
9208 ErrorPopUp("Note", str);
\r
9213 char *title, *question, *replyPrefix;
\r
9218 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9220 static QuestionParams *qp;
\r
9221 char reply[MSG_SIZ];
\r
9224 switch (message) {
\r
9225 case WM_INITDIALOG:
\r
9226 qp = (QuestionParams *) lParam;
\r
9227 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9228 SetWindowText(hDlg, qp->title);
\r
9229 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9230 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9234 switch (LOWORD(wParam)) {
\r
9236 strcpy(reply, qp->replyPrefix);
\r
9237 if (*reply) strcat(reply, " ");
\r
9238 len = strlen(reply);
\r
9239 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9240 strcat(reply, "\n");
\r
9241 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9242 EndDialog(hDlg, TRUE);
\r
9243 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9246 EndDialog(hDlg, FALSE);
\r
9257 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9259 QuestionParams qp;
\r
9263 qp.question = question;
\r
9264 qp.replyPrefix = replyPrefix;
\r
9266 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9267 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9268 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9269 FreeProcInstance(lpProc);
\r
9272 /* [AS] Pick FRC position */
\r
9273 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9275 static int * lpIndexFRC;
\r
9281 case WM_INITDIALOG:
\r
9282 lpIndexFRC = (int *) lParam;
\r
9284 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9286 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9287 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9288 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9289 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9294 switch( LOWORD(wParam) ) {
\r
9296 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9297 EndDialog( hDlg, 0 );
\r
9298 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9301 EndDialog( hDlg, 1 );
\r
9303 case IDC_NFG_Edit:
\r
9304 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9305 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9307 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9310 case IDC_NFG_Random:
\r
9311 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9312 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9325 int index = appData.defaultFrcPosition;
\r
9326 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9328 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9330 if( result == 0 ) {
\r
9331 appData.defaultFrcPosition = index;
\r
9337 /* [AS] Game list options */
\r
9343 static GLT_Item GLT_ItemInfo[] = {
\r
9344 { GLT_EVENT, "Event" },
\r
9345 { GLT_SITE, "Site" },
\r
9346 { GLT_DATE, "Date" },
\r
9347 { GLT_ROUND, "Round" },
\r
9348 { GLT_PLAYERS, "Players" },
\r
9349 { GLT_RESULT, "Result" },
\r
9350 { GLT_WHITE_ELO, "White Rating" },
\r
9351 { GLT_BLACK_ELO, "Black Rating" },
\r
9352 { GLT_TIME_CONTROL,"Time Control" },
\r
9353 { GLT_VARIANT, "Variant" },
\r
9354 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9355 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9359 const char * GLT_FindItem( char id )
\r
9361 const char * result = 0;
\r
9363 GLT_Item * list = GLT_ItemInfo;
\r
9365 while( list->id != 0 ) {
\r
9366 if( list->id == id ) {
\r
9367 result = list->name;
\r
9377 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9379 const char * name = GLT_FindItem( id );
\r
9382 if( index >= 0 ) {
\r
9383 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9386 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9391 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9395 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9398 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9402 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9404 pc = GLT_ALL_TAGS;
\r
9407 if( strchr( tags, *pc ) == 0 ) {
\r
9408 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9413 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9416 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9418 char result = '\0';
\r
9421 GLT_Item * list = GLT_ItemInfo;
\r
9423 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9424 while( list->id != 0 ) {
\r
9425 if( strcmp( list->name, name ) == 0 ) {
\r
9426 result = list->id;
\r
9437 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9439 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9440 int idx2 = idx1 + delta;
\r
9441 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9443 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9446 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9447 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9448 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9449 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9453 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9455 static char glt[64];
\r
9456 static char * lpUserGLT;
\r
9460 case WM_INITDIALOG:
\r
9461 lpUserGLT = (char *) lParam;
\r
9463 strcpy( glt, lpUserGLT );
\r
9465 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9467 /* Initialize list */
\r
9468 GLT_TagsToList( hDlg, glt );
\r
9470 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9475 switch( LOWORD(wParam) ) {
\r
9478 char * pc = lpUserGLT;
\r
9480 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9484 id = GLT_ListItemToTag( hDlg, idx );
\r
9488 } while( id != '\0' );
\r
9490 EndDialog( hDlg, 0 );
\r
9493 EndDialog( hDlg, 1 );
\r
9496 case IDC_GLT_Default:
\r
9497 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9498 GLT_TagsToList( hDlg, glt );
\r
9501 case IDC_GLT_Restore:
\r
9502 strcpy( glt, lpUserGLT );
\r
9503 GLT_TagsToList( hDlg, glt );
\r
9507 GLT_MoveSelection( hDlg, -1 );
\r
9510 case IDC_GLT_Down:
\r
9511 GLT_MoveSelection( hDlg, +1 );
\r
9521 int GameListOptions()
\r
9525 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9527 strcpy( glt, appData.gameListTags );
\r
9529 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9531 if( result == 0 ) {
\r
9532 /* [AS] Memory leak here! */
\r
9533 appData.gameListTags = strdup( glt );
\r
9541 DisplayIcsInteractionTitle(char *str)
\r
9543 char consoleTitle[MSG_SIZ];
\r
9545 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9546 SetWindowText(hwndConsole, consoleTitle);
\r
9550 DrawPosition(int fullRedraw, Board board)
\r
9552 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9555 void NotifyFrontendLogin()
\r
9558 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9564 fromX = fromY = -1;
\r
9565 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9566 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9567 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9568 dragInfo.lastpos = dragInfo.pos;
\r
9569 dragInfo.start.x = dragInfo.start.y = -1;
\r
9570 dragInfo.from = dragInfo.start;
\r
9572 DrawPosition(TRUE, NULL);
\r
9578 CommentPopUp(char *title, char *str)
\r
9580 HWND hwnd = GetActiveWindow();
\r
9581 EitherCommentPopUp(0, title, str, FALSE);
\r
9583 SetActiveWindow(hwnd);
\r
9587 CommentPopDown(void)
\r
9589 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9590 if (commentDialog) {
\r
9591 ShowWindow(commentDialog, SW_HIDE);
\r
9593 commentDialogUp = FALSE;
\r
9597 EditCommentPopUp(int index, char *title, char *str)
\r
9599 EitherCommentPopUp(index, title, str, TRUE);
\r
9606 MyPlaySound(&sounds[(int)SoundMove]);
\r
9609 VOID PlayIcsWinSound()
\r
9611 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9614 VOID PlayIcsLossSound()
\r
9616 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9619 VOID PlayIcsDrawSound()
\r
9621 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9624 VOID PlayIcsUnfinishedSound()
\r
9626 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9632 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9640 consoleEcho = TRUE;
\r
9641 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9642 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9643 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9652 consoleEcho = FALSE;
\r
9653 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9654 /* This works OK: set text and background both to the same color */
\r
9656 cf.crTextColor = COLOR_ECHOOFF;
\r
9657 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9658 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9661 /* No Raw()...? */
\r
9663 void Colorize(ColorClass cc, int continuation)
\r
9665 currentColorClass = cc;
\r
9666 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9667 consoleCF.crTextColor = textAttribs[cc].color;
\r
9668 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9669 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9675 static char buf[MSG_SIZ];
\r
9676 DWORD bufsiz = MSG_SIZ;
\r
9678 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9679 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9681 if (!GetUserName(buf, &bufsiz)) {
\r
9682 /*DisplayError("Error getting user name", GetLastError());*/
\r
9683 strcpy(buf, "User");
\r
9691 static char buf[MSG_SIZ];
\r
9692 DWORD bufsiz = MSG_SIZ;
\r
9694 if (!GetComputerName(buf, &bufsiz)) {
\r
9695 /*DisplayError("Error getting host name", GetLastError());*/
\r
9696 strcpy(buf, "Unknown");
\r
9703 ClockTimerRunning()
\r
9705 return clockTimerEvent != 0;
\r
9711 if (clockTimerEvent == 0) return FALSE;
\r
9712 KillTimer(hwndMain, clockTimerEvent);
\r
9713 clockTimerEvent = 0;
\r
9718 StartClockTimer(long millisec)
\r
9720 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9721 (UINT) millisec, NULL);
\r
9725 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9728 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9730 if(appData.noGUI) return;
\r
9731 hdc = GetDC(hwndMain);
\r
9732 if (!IsIconic(hwndMain)) {
\r
9733 DisplayAClock(hdc, timeRemaining, highlight,
\r
9734 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9736 if (highlight && iconCurrent == iconBlack) {
\r
9737 iconCurrent = iconWhite;
\r
9738 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9739 if (IsIconic(hwndMain)) {
\r
9740 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9743 (void) ReleaseDC(hwndMain, hdc);
\r
9745 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9749 DisplayBlackClock(long timeRemaining, int highlight)
\r
9752 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9754 if(appData.noGUI) return;
\r
9755 hdc = GetDC(hwndMain);
\r
9756 if (!IsIconic(hwndMain)) {
\r
9757 DisplayAClock(hdc, timeRemaining, highlight,
\r
9758 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9760 if (highlight && iconCurrent == iconWhite) {
\r
9761 iconCurrent = iconBlack;
\r
9762 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9763 if (IsIconic(hwndMain)) {
\r
9764 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9767 (void) ReleaseDC(hwndMain, hdc);
\r
9769 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9774 LoadGameTimerRunning()
\r
9776 return loadGameTimerEvent != 0;
\r
9780 StopLoadGameTimer()
\r
9782 if (loadGameTimerEvent == 0) return FALSE;
\r
9783 KillTimer(hwndMain, loadGameTimerEvent);
\r
9784 loadGameTimerEvent = 0;
\r
9789 StartLoadGameTimer(long millisec)
\r
9791 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9792 (UINT) millisec, NULL);
\r
9800 char fileTitle[MSG_SIZ];
\r
9802 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9803 f = OpenFileDialog(hwndMain, "a", defName,
\r
9804 appData.oldSaveStyle ? "gam" : "pgn",
\r
9806 "Save Game to File", NULL, fileTitle, NULL);
\r
9808 SaveGame(f, 0, "");
\r
9815 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9817 if (delayedTimerEvent != 0) {
\r
9818 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9819 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9821 KillTimer(hwndMain, delayedTimerEvent);
\r
9822 delayedTimerEvent = 0;
\r
9823 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9824 delayedTimerCallback();
\r
9826 delayedTimerCallback = cb;
\r
9827 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9828 (UINT) millisec, NULL);
\r
9831 DelayedEventCallback
\r
9834 if (delayedTimerEvent) {
\r
9835 return delayedTimerCallback;
\r
9842 CancelDelayedEvent()
\r
9844 if (delayedTimerEvent) {
\r
9845 KillTimer(hwndMain, delayedTimerEvent);
\r
9846 delayedTimerEvent = 0;
\r
9850 DWORD GetWin32Priority(int nice)
\r
9851 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9853 REALTIME_PRIORITY_CLASS 0x00000100
\r
9854 HIGH_PRIORITY_CLASS 0x00000080
\r
9855 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9856 NORMAL_PRIORITY_CLASS 0x00000020
\r
9857 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9858 IDLE_PRIORITY_CLASS 0x00000040
\r
9860 if (nice < -15) return 0x00000080;
\r
9861 if (nice < 0) return 0x00008000;
\r
9862 if (nice == 0) return 0x00000020;
\r
9863 if (nice < 15) return 0x00004000;
\r
9864 return 0x00000040;
\r
9867 /* Start a child process running the given program.
\r
9868 The process's standard output can be read from "from", and its
\r
9869 standard input can be written to "to".
\r
9870 Exit with fatal error if anything goes wrong.
\r
9871 Returns an opaque pointer that can be used to destroy the process
\r
9875 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9877 #define BUFSIZE 4096
\r
9879 HANDLE hChildStdinRd, hChildStdinWr,
\r
9880 hChildStdoutRd, hChildStdoutWr;
\r
9881 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9882 SECURITY_ATTRIBUTES saAttr;
\r
9884 PROCESS_INFORMATION piProcInfo;
\r
9885 STARTUPINFO siStartInfo;
\r
9887 char buf[MSG_SIZ];
\r
9890 if (appData.debugMode) {
\r
9891 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9896 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9897 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9898 saAttr.bInheritHandle = TRUE;
\r
9899 saAttr.lpSecurityDescriptor = NULL;
\r
9902 * The steps for redirecting child's STDOUT:
\r
9903 * 1. Create anonymous pipe to be STDOUT for child.
\r
9904 * 2. Create a noninheritable duplicate of read handle,
\r
9905 * and close the inheritable read handle.
\r
9908 /* Create a pipe for the child's STDOUT. */
\r
9909 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9910 return GetLastError();
\r
9913 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9914 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9915 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9916 FALSE, /* not inherited */
\r
9917 DUPLICATE_SAME_ACCESS);
\r
9919 return GetLastError();
\r
9921 CloseHandle(hChildStdoutRd);
\r
9924 * The steps for redirecting child's STDIN:
\r
9925 * 1. Create anonymous pipe to be STDIN for child.
\r
9926 * 2. Create a noninheritable duplicate of write handle,
\r
9927 * and close the inheritable write handle.
\r
9930 /* Create a pipe for the child's STDIN. */
\r
9931 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9932 return GetLastError();
\r
9935 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9936 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9937 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9938 FALSE, /* not inherited */
\r
9939 DUPLICATE_SAME_ACCESS);
\r
9941 return GetLastError();
\r
9943 CloseHandle(hChildStdinWr);
\r
9945 /* Arrange to (1) look in dir for the child .exe file, and
\r
9946 * (2) have dir be the child's working directory. Interpret
\r
9947 * dir relative to the directory WinBoard loaded from. */
\r
9948 GetCurrentDirectory(MSG_SIZ, buf);
\r
9949 SetCurrentDirectory(installDir);
\r
9950 SetCurrentDirectory(dir);
\r
9952 /* Now create the child process. */
\r
9954 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9955 siStartInfo.lpReserved = NULL;
\r
9956 siStartInfo.lpDesktop = NULL;
\r
9957 siStartInfo.lpTitle = NULL;
\r
9958 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9959 siStartInfo.cbReserved2 = 0;
\r
9960 siStartInfo.lpReserved2 = NULL;
\r
9961 siStartInfo.hStdInput = hChildStdinRd;
\r
9962 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9963 siStartInfo.hStdError = hChildStdoutWr;
\r
9965 fSuccess = CreateProcess(NULL,
\r
9966 cmdLine, /* command line */
\r
9967 NULL, /* process security attributes */
\r
9968 NULL, /* primary thread security attrs */
\r
9969 TRUE, /* handles are inherited */
\r
9970 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9971 NULL, /* use parent's environment */
\r
9973 &siStartInfo, /* STARTUPINFO pointer */
\r
9974 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9976 err = GetLastError();
\r
9977 SetCurrentDirectory(buf); /* return to prev directory */
\r
9982 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9983 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9984 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9987 /* Close the handles we don't need in the parent */
\r
9988 CloseHandle(piProcInfo.hThread);
\r
9989 CloseHandle(hChildStdinRd);
\r
9990 CloseHandle(hChildStdoutWr);
\r
9992 /* Prepare return value */
\r
9993 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9994 cp->kind = CPReal;
\r
9995 cp->hProcess = piProcInfo.hProcess;
\r
9996 cp->pid = piProcInfo.dwProcessId;
\r
9997 cp->hFrom = hChildStdoutRdDup;
\r
9998 cp->hTo = hChildStdinWrDup;
\r
10000 *pr = (void *) cp;
\r
10002 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10003 2000 where engines sometimes don't see the initial command(s)
\r
10004 from WinBoard and hang. I don't understand how that can happen,
\r
10005 but the Sleep is harmless, so I've put it in. Others have also
\r
10006 reported what may be the same problem, so hopefully this will fix
\r
10007 it for them too. */
\r
10015 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10017 ChildProc *cp; int result;
\r
10019 cp = (ChildProc *) pr;
\r
10020 if (cp == NULL) return;
\r
10022 switch (cp->kind) {
\r
10024 /* TerminateProcess is considered harmful, so... */
\r
10025 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10026 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10027 /* The following doesn't work because the chess program
\r
10028 doesn't "have the same console" as WinBoard. Maybe
\r
10029 we could arrange for this even though neither WinBoard
\r
10030 nor the chess program uses a console for stdio? */
\r
10031 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10033 /* [AS] Special termination modes for misbehaving programs... */
\r
10034 if( signal == 9 ) {
\r
10035 result = TerminateProcess( cp->hProcess, 0 );
\r
10037 if ( appData.debugMode) {
\r
10038 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10041 else if( signal == 10 ) {
\r
10042 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10044 if( dw != WAIT_OBJECT_0 ) {
\r
10045 result = TerminateProcess( cp->hProcess, 0 );
\r
10047 if ( appData.debugMode) {
\r
10048 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10054 CloseHandle(cp->hProcess);
\r
10058 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10062 closesocket(cp->sock);
\r
10067 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10068 closesocket(cp->sock);
\r
10069 closesocket(cp->sock2);
\r
10077 InterruptChildProcess(ProcRef pr)
\r
10081 cp = (ChildProc *) pr;
\r
10082 if (cp == NULL) return;
\r
10083 switch (cp->kind) {
\r
10085 /* The following doesn't work because the chess program
\r
10086 doesn't "have the same console" as WinBoard. Maybe
\r
10087 we could arrange for this even though neither WinBoard
\r
10088 nor the chess program uses a console for stdio */
\r
10089 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10094 /* Can't interrupt */
\r
10098 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10105 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10107 char cmdLine[MSG_SIZ];
\r
10109 if (port[0] == NULLCHAR) {
\r
10110 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10112 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10114 return StartChildProcess(cmdLine, "", pr);
\r
10118 /* Code to open TCP sockets */
\r
10121 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10126 struct sockaddr_in sa, mysa;
\r
10127 struct hostent FAR *hp;
\r
10128 unsigned short uport;
\r
10129 WORD wVersionRequested;
\r
10132 /* Initialize socket DLL */
\r
10133 wVersionRequested = MAKEWORD(1, 1);
\r
10134 err = WSAStartup(wVersionRequested, &wsaData);
\r
10135 if (err != 0) return err;
\r
10137 /* Make socket */
\r
10138 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10139 err = WSAGetLastError();
\r
10144 /* Bind local address using (mostly) don't-care values.
\r
10146 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10147 mysa.sin_family = AF_INET;
\r
10148 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10149 uport = (unsigned short) 0;
\r
10150 mysa.sin_port = htons(uport);
\r
10151 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10152 == SOCKET_ERROR) {
\r
10153 err = WSAGetLastError();
\r
10158 /* Resolve remote host name */
\r
10159 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10160 if (!(hp = gethostbyname(host))) {
\r
10161 unsigned int b0, b1, b2, b3;
\r
10163 err = WSAGetLastError();
\r
10165 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10166 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10167 hp->h_addrtype = AF_INET;
\r
10168 hp->h_length = 4;
\r
10169 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10170 hp->h_addr_list[0] = (char *) malloc(4);
\r
10171 hp->h_addr_list[0][0] = (char) b0;
\r
10172 hp->h_addr_list[0][1] = (char) b1;
\r
10173 hp->h_addr_list[0][2] = (char) b2;
\r
10174 hp->h_addr_list[0][3] = (char) b3;
\r
10180 sa.sin_family = hp->h_addrtype;
\r
10181 uport = (unsigned short) atoi(port);
\r
10182 sa.sin_port = htons(uport);
\r
10183 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10185 /* Make connection */
\r
10186 if (connect(s, (struct sockaddr *) &sa,
\r
10187 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10188 err = WSAGetLastError();
\r
10193 /* Prepare return value */
\r
10194 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10195 cp->kind = CPSock;
\r
10197 *pr = (ProcRef *) cp;
\r
10203 OpenCommPort(char *name, ProcRef *pr)
\r
10208 char fullname[MSG_SIZ];
\r
10210 if (*name != '\\')
\r
10211 sprintf(fullname, "\\\\.\\%s", name);
\r
10213 strcpy(fullname, name);
\r
10215 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10216 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10217 if (h == (HANDLE) -1) {
\r
10218 return GetLastError();
\r
10222 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10224 /* Accumulate characters until a 100ms pause, then parse */
\r
10225 ct.ReadIntervalTimeout = 100;
\r
10226 ct.ReadTotalTimeoutMultiplier = 0;
\r
10227 ct.ReadTotalTimeoutConstant = 0;
\r
10228 ct.WriteTotalTimeoutMultiplier = 0;
\r
10229 ct.WriteTotalTimeoutConstant = 0;
\r
10230 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10232 /* Prepare return value */
\r
10233 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10234 cp->kind = CPComm;
\r
10237 *pr = (ProcRef *) cp;
\r
10243 OpenLoopback(ProcRef *pr)
\r
10245 DisplayFatalError("Not implemented", 0, 1);
\r
10251 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10255 SOCKET s, s2, s3;
\r
10256 struct sockaddr_in sa, mysa;
\r
10257 struct hostent FAR *hp;
\r
10258 unsigned short uport;
\r
10259 WORD wVersionRequested;
\r
10262 char stderrPortStr[MSG_SIZ];
\r
10264 /* Initialize socket DLL */
\r
10265 wVersionRequested = MAKEWORD(1, 1);
\r
10266 err = WSAStartup(wVersionRequested, &wsaData);
\r
10267 if (err != 0) return err;
\r
10269 /* Resolve remote host name */
\r
10270 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10271 if (!(hp = gethostbyname(host))) {
\r
10272 unsigned int b0, b1, b2, b3;
\r
10274 err = WSAGetLastError();
\r
10276 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10277 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10278 hp->h_addrtype = AF_INET;
\r
10279 hp->h_length = 4;
\r
10280 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10281 hp->h_addr_list[0] = (char *) malloc(4);
\r
10282 hp->h_addr_list[0][0] = (char) b0;
\r
10283 hp->h_addr_list[0][1] = (char) b1;
\r
10284 hp->h_addr_list[0][2] = (char) b2;
\r
10285 hp->h_addr_list[0][3] = (char) b3;
\r
10291 sa.sin_family = hp->h_addrtype;
\r
10292 uport = (unsigned short) 514;
\r
10293 sa.sin_port = htons(uport);
\r
10294 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10296 /* Bind local socket to unused "privileged" port address
\r
10298 s = INVALID_SOCKET;
\r
10299 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10300 mysa.sin_family = AF_INET;
\r
10301 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10302 for (fromPort = 1023;; fromPort--) {
\r
10303 if (fromPort < 0) {
\r
10305 return WSAEADDRINUSE;
\r
10307 if (s == INVALID_SOCKET) {
\r
10308 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10309 err = WSAGetLastError();
\r
10314 uport = (unsigned short) fromPort;
\r
10315 mysa.sin_port = htons(uport);
\r
10316 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10317 == SOCKET_ERROR) {
\r
10318 err = WSAGetLastError();
\r
10319 if (err == WSAEADDRINUSE) continue;
\r
10323 if (connect(s, (struct sockaddr *) &sa,
\r
10324 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10325 err = WSAGetLastError();
\r
10326 if (err == WSAEADDRINUSE) {
\r
10337 /* Bind stderr local socket to unused "privileged" port address
\r
10339 s2 = INVALID_SOCKET;
\r
10340 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10341 mysa.sin_family = AF_INET;
\r
10342 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10343 for (fromPort = 1023;; fromPort--) {
\r
10344 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10345 if (fromPort < 0) {
\r
10346 (void) closesocket(s);
\r
10348 return WSAEADDRINUSE;
\r
10350 if (s2 == INVALID_SOCKET) {
\r
10351 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10352 err = WSAGetLastError();
\r
10358 uport = (unsigned short) fromPort;
\r
10359 mysa.sin_port = htons(uport);
\r
10360 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10361 == SOCKET_ERROR) {
\r
10362 err = WSAGetLastError();
\r
10363 if (err == WSAEADDRINUSE) continue;
\r
10364 (void) closesocket(s);
\r
10368 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10369 err = WSAGetLastError();
\r
10370 if (err == WSAEADDRINUSE) {
\r
10372 s2 = INVALID_SOCKET;
\r
10375 (void) closesocket(s);
\r
10376 (void) closesocket(s2);
\r
10382 prevStderrPort = fromPort; // remember port used
\r
10383 sprintf(stderrPortStr, "%d", fromPort);
\r
10385 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10386 err = WSAGetLastError();
\r
10387 (void) closesocket(s);
\r
10388 (void) closesocket(s2);
\r
10393 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10394 err = WSAGetLastError();
\r
10395 (void) closesocket(s);
\r
10396 (void) closesocket(s2);
\r
10400 if (*user == NULLCHAR) user = UserName();
\r
10401 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10402 err = WSAGetLastError();
\r
10403 (void) closesocket(s);
\r
10404 (void) closesocket(s2);
\r
10408 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10409 err = WSAGetLastError();
\r
10410 (void) closesocket(s);
\r
10411 (void) closesocket(s2);
\r
10416 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10417 err = WSAGetLastError();
\r
10418 (void) closesocket(s);
\r
10419 (void) closesocket(s2);
\r
10423 (void) closesocket(s2); /* Stop listening */
\r
10425 /* Prepare return value */
\r
10426 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10427 cp->kind = CPRcmd;
\r
10430 *pr = (ProcRef *) cp;
\r
10437 AddInputSource(ProcRef pr, int lineByLine,
\r
10438 InputCallback func, VOIDSTAR closure)
\r
10440 InputSource *is, *is2 = NULL;
\r
10441 ChildProc *cp = (ChildProc *) pr;
\r
10443 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10444 is->lineByLine = lineByLine;
\r
10446 is->closure = closure;
\r
10447 is->second = NULL;
\r
10448 is->next = is->buf;
\r
10449 if (pr == NoProc) {
\r
10450 is->kind = CPReal;
\r
10451 consoleInputSource = is;
\r
10453 is->kind = cp->kind;
\r
10455 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10456 we create all threads suspended so that the is->hThread variable can be
\r
10457 safely assigned, then let the threads start with ResumeThread.
\r
10459 switch (cp->kind) {
\r
10461 is->hFile = cp->hFrom;
\r
10462 cp->hFrom = NULL; /* now owned by InputThread */
\r
10464 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10465 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10469 is->hFile = cp->hFrom;
\r
10470 cp->hFrom = NULL; /* now owned by InputThread */
\r
10472 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10473 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10477 is->sock = cp->sock;
\r
10479 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10480 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10484 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10486 is->sock = cp->sock;
\r
10487 is->second = is2;
\r
10488 is2->sock = cp->sock2;
\r
10489 is2->second = is2;
\r
10491 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10492 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10494 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10495 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10499 if( is->hThread != NULL ) {
\r
10500 ResumeThread( is->hThread );
\r
10503 if( is2 != NULL && is2->hThread != NULL ) {
\r
10504 ResumeThread( is2->hThread );
\r
10508 return (InputSourceRef) is;
\r
10512 RemoveInputSource(InputSourceRef isr)
\r
10516 is = (InputSource *) isr;
\r
10517 is->hThread = NULL; /* tell thread to stop */
\r
10518 CloseHandle(is->hThread);
\r
10519 if (is->second != NULL) {
\r
10520 is->second->hThread = NULL;
\r
10521 CloseHandle(is->second->hThread);
\r
10527 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10530 int outCount = SOCKET_ERROR;
\r
10531 ChildProc *cp = (ChildProc *) pr;
\r
10532 static OVERLAPPED ovl;
\r
10534 if (pr == NoProc) {
\r
10535 ConsoleOutput(message, count, FALSE);
\r
10539 if (ovl.hEvent == NULL) {
\r
10540 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10542 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10544 switch (cp->kind) {
\r
10547 outCount = send(cp->sock, message, count, 0);
\r
10548 if (outCount == SOCKET_ERROR) {
\r
10549 *outError = WSAGetLastError();
\r
10551 *outError = NO_ERROR;
\r
10556 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10557 &dOutCount, NULL)) {
\r
10558 *outError = NO_ERROR;
\r
10559 outCount = (int) dOutCount;
\r
10561 *outError = GetLastError();
\r
10566 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10567 &dOutCount, &ovl);
\r
10568 if (*outError == NO_ERROR) {
\r
10569 outCount = (int) dOutCount;
\r
10577 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10580 /* Ignore delay, not implemented for WinBoard */
\r
10581 return OutputToProcess(pr, message, count, outError);
\r
10586 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10587 char *buf, int count, int error)
\r
10589 DisplayFatalError("Not implemented", 0, 1);
\r
10592 /* see wgamelist.c for Game List functions */
\r
10593 /* see wedittags.c for Edit Tags functions */
\r
10600 char buf[MSG_SIZ];
\r
10603 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10604 f = fopen(buf, "r");
\r
10606 ProcessICSInitScript(f);
\r
10614 StartAnalysisClock()
\r
10616 if (analysisTimerEvent) return;
\r
10617 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10618 (UINT) 2000, NULL);
\r
10622 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10624 static HANDLE hwndText;
\r
10626 static int sizeX, sizeY;
\r
10627 int newSizeX, newSizeY, flags;
\r
10630 switch (message) {
\r
10631 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10632 /* Initialize the dialog items */
\r
10633 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10634 SetWindowText(hDlg, analysisTitle);
\r
10635 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10636 /* Size and position the dialog */
\r
10637 if (!analysisDialog) {
\r
10638 analysisDialog = hDlg;
\r
10639 flags = SWP_NOZORDER;
\r
10640 GetClientRect(hDlg, &rect);
\r
10641 sizeX = rect.right;
\r
10642 sizeY = rect.bottom;
\r
10643 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10644 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10645 WINDOWPLACEMENT wp;
\r
10646 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10647 wp.length = sizeof(WINDOWPLACEMENT);
\r
10649 wp.showCmd = SW_SHOW;
\r
10650 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10651 wp.rcNormalPosition.left = analysisX;
\r
10652 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10653 wp.rcNormalPosition.top = analysisY;
\r
10654 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10655 SetWindowPlacement(hDlg, &wp);
\r
10657 GetClientRect(hDlg, &rect);
\r
10658 newSizeX = rect.right;
\r
10659 newSizeY = rect.bottom;
\r
10660 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10661 newSizeX, newSizeY);
\r
10662 sizeX = newSizeX;
\r
10663 sizeY = newSizeY;
\r
10668 case WM_COMMAND: /* message: received a command */
\r
10669 switch (LOWORD(wParam)) {
\r
10671 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10672 ExitAnalyzeMode();
\r
10684 newSizeX = LOWORD(lParam);
\r
10685 newSizeY = HIWORD(lParam);
\r
10686 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10687 sizeX = newSizeX;
\r
10688 sizeY = newSizeY;
\r
10691 case WM_GETMINMAXINFO:
\r
10692 /* Prevent resizing window too small */
\r
10693 mmi = (MINMAXINFO *) lParam;
\r
10694 mmi->ptMinTrackSize.x = 100;
\r
10695 mmi->ptMinTrackSize.y = 100;
\r
10702 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10704 highlightInfo.sq[0].x = fromX;
\r
10705 highlightInfo.sq[0].y = fromY;
\r
10706 highlightInfo.sq[1].x = toX;
\r
10707 highlightInfo.sq[1].y = toY;
\r
10711 ClearHighlights()
\r
10713 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10714 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10718 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10720 premoveHighlightInfo.sq[0].x = fromX;
\r
10721 premoveHighlightInfo.sq[0].y = fromY;
\r
10722 premoveHighlightInfo.sq[1].x = toX;
\r
10723 premoveHighlightInfo.sq[1].y = toY;
\r
10727 ClearPremoveHighlights()
\r
10729 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10730 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10734 ShutDownFrontEnd()
\r
10736 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10737 DeleteClipboardTempFiles();
\r
10743 if (IsIconic(hwndMain))
\r
10744 ShowWindow(hwndMain, SW_RESTORE);
\r
10746 SetActiveWindow(hwndMain);
\r
10750 * Prototypes for animation support routines
\r
10752 static void ScreenSquare(int column, int row, POINT * pt);
\r
10753 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10754 POINT frames[], int * nFrames);
\r
10758 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10759 { // [HGM] atomic: animate blast wave
\r
10761 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10762 explodeInfo.fromX = fromX;
\r
10763 explodeInfo.fromY = fromY;
\r
10764 explodeInfo.toX = toX;
\r
10765 explodeInfo.toY = toY;
\r
10766 for(i=1; i<nFrames; i++) {
\r
10767 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10768 DrawPosition(FALSE, NULL);
\r
10769 Sleep(appData.animSpeed);
\r
10771 explodeInfo.radius = 0;
\r
10772 DrawPosition(TRUE, NULL);
\r
10775 #define kFactor 4
\r
10778 AnimateMove(board, fromX, fromY, toX, toY)
\r
10785 ChessSquare piece;
\r
10786 POINT start, finish, mid;
\r
10787 POINT frames[kFactor * 2 + 1];
\r
10790 if (!appData.animate) return;
\r
10791 if (doingSizing) return;
\r
10792 if (fromY < 0 || fromX < 0) return;
\r
10793 piece = board[fromY][fromX];
\r
10794 if (piece >= EmptySquare) return;
\r
10796 ScreenSquare(fromX, fromY, &start);
\r
10797 ScreenSquare(toX, toY, &finish);
\r
10799 /* All pieces except knights move in straight line */
\r
10800 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10801 mid.x = start.x + (finish.x - start.x) / 2;
\r
10802 mid.y = start.y + (finish.y - start.y) / 2;
\r
10804 /* Knight: make diagonal movement then straight */
\r
10805 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10806 mid.x = start.x + (finish.x - start.x) / 2;
\r
10807 mid.y = finish.y;
\r
10809 mid.x = finish.x;
\r
10810 mid.y = start.y + (finish.y - start.y) / 2;
\r
10814 /* Don't use as many frames for very short moves */
\r
10815 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10816 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10818 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10820 animInfo.from.x = fromX;
\r
10821 animInfo.from.y = fromY;
\r
10822 animInfo.to.x = toX;
\r
10823 animInfo.to.y = toY;
\r
10824 animInfo.lastpos = start;
\r
10825 animInfo.piece = piece;
\r
10826 for (n = 0; n < nFrames; n++) {
\r
10827 animInfo.pos = frames[n];
\r
10828 DrawPosition(FALSE, NULL);
\r
10829 animInfo.lastpos = animInfo.pos;
\r
10830 Sleep(appData.animSpeed);
\r
10832 animInfo.pos = finish;
\r
10833 DrawPosition(FALSE, NULL);
\r
10834 animInfo.piece = EmptySquare;
\r
10835 if(gameInfo.variant == VariantAtomic &&
\r
10836 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10837 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10840 /* Convert board position to corner of screen rect and color */
\r
10843 ScreenSquare(column, row, pt)
\r
10844 int column; int row; POINT * pt;
\r
10847 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10848 pt->y = lineGap + row * (squareSize + lineGap);
\r
10850 pt->x = lineGap + column * (squareSize + lineGap);
\r
10851 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10855 /* Generate a series of frame coords from start->mid->finish.
\r
10856 The movement rate doubles until the half way point is
\r
10857 reached, then halves back down to the final destination,
\r
10858 which gives a nice slow in/out effect. The algorithmn
\r
10859 may seem to generate too many intermediates for short
\r
10860 moves, but remember that the purpose is to attract the
\r
10861 viewers attention to the piece about to be moved and
\r
10862 then to where it ends up. Too few frames would be less
\r
10866 Tween(start, mid, finish, factor, frames, nFrames)
\r
10867 POINT * start; POINT * mid;
\r
10868 POINT * finish; int factor;
\r
10869 POINT frames[]; int * nFrames;
\r
10871 int n, fraction = 1, count = 0;
\r
10873 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10874 for (n = 0; n < factor; n++)
\r
10876 for (n = 0; n < factor; n++) {
\r
10877 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10878 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10880 fraction = fraction / 2;
\r
10884 frames[count] = *mid;
\r
10887 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10889 for (n = 0; n < factor; n++) {
\r
10890 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10891 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10893 fraction = fraction * 2;
\r
10895 *nFrames = count;
\r
10899 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10901 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10903 EvalGraphSet( first, last, current, pvInfoList );
\r
10906 void SetProgramStats( FrontEndProgramStats * stats )
\r
10908 EngineOutputUpdate( stats );
\r