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 SAY("new game enter a move to play against the computer with white");
\r
5637 case IDM_NewGameFRC:
\r
5638 if( NewGameFRC() == 0 ) {
\r
5643 case IDM_NewVariant:
\r
5644 NewVariantPopup(hwnd);
\r
5647 case IDM_LoadGame:
\r
5648 LoadGameDialog(hwnd, "Load Game from File");
\r
5651 case IDM_LoadNextGame:
\r
5655 case IDM_LoadPrevGame:
\r
5659 case IDM_ReloadGame:
\r
5663 case IDM_LoadPosition:
\r
5664 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5665 Reset(FALSE, TRUE);
\r
5668 f = OpenFileDialog(hwnd, "rb", "",
\r
5669 appData.oldSaveStyle ? "pos" : "fen",
\r
5671 "Load Position from File", &number, fileTitle, NULL);
\r
5673 LoadPosition(f, number, fileTitle);
\r
5677 case IDM_LoadNextPosition:
\r
5678 ReloadPosition(1);
\r
5681 case IDM_LoadPrevPosition:
\r
5682 ReloadPosition(-1);
\r
5685 case IDM_ReloadPosition:
\r
5686 ReloadPosition(0);
\r
5689 case IDM_SaveGame:
\r
5690 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5691 f = OpenFileDialog(hwnd, "a", defName,
\r
5692 appData.oldSaveStyle ? "gam" : "pgn",
\r
5694 "Save Game to File", NULL, fileTitle, NULL);
\r
5696 SaveGame(f, 0, "");
\r
5700 case IDM_SavePosition:
\r
5701 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5702 f = OpenFileDialog(hwnd, "a", defName,
\r
5703 appData.oldSaveStyle ? "pos" : "fen",
\r
5705 "Save Position to File", NULL, fileTitle, NULL);
\r
5707 SavePosition(f, 0, "");
\r
5711 case IDM_SaveDiagram:
\r
5712 defName = "diagram";
\r
5713 f = OpenFileDialog(hwnd, "wb", defName,
\r
5716 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5722 case IDM_CopyGame:
\r
5723 CopyGameToClipboard();
\r
5726 case IDM_PasteGame:
\r
5727 PasteGameFromClipboard();
\r
5730 case IDM_CopyGameListToClipboard:
\r
5731 CopyGameListToClipboard();
\r
5734 /* [AS] Autodetect FEN or PGN data */
\r
5735 case IDM_PasteAny:
\r
5736 PasteGameOrFENFromClipboard();
\r
5739 /* [AS] Move history */
\r
5740 case IDM_ShowMoveHistory:
\r
5741 if( MoveHistoryIsUp() ) {
\r
5742 MoveHistoryPopDown();
\r
5745 MoveHistoryPopUp();
\r
5749 /* [AS] Eval graph */
\r
5750 case IDM_ShowEvalGraph:
\r
5751 if( EvalGraphIsUp() ) {
\r
5752 EvalGraphPopDown();
\r
5756 SetFocus(hwndMain);
\r
5760 /* [AS] Engine output */
\r
5761 case IDM_ShowEngineOutput:
\r
5762 if( EngineOutputIsUp() ) {
\r
5763 EngineOutputPopDown();
\r
5766 EngineOutputPopUp();
\r
5770 /* [AS] User adjudication */
\r
5771 case IDM_UserAdjudication_White:
\r
5772 UserAdjudicationEvent( +1 );
\r
5775 case IDM_UserAdjudication_Black:
\r
5776 UserAdjudicationEvent( -1 );
\r
5779 case IDM_UserAdjudication_Draw:
\r
5780 UserAdjudicationEvent( 0 );
\r
5783 /* [AS] Game list options dialog */
\r
5784 case IDM_GameListOptions:
\r
5785 GameListOptions();
\r
5792 case IDM_CopyPosition:
\r
5793 CopyFENToClipboard();
\r
5796 case IDM_PastePosition:
\r
5797 PasteFENFromClipboard();
\r
5800 case IDM_MailMove:
\r
5804 case IDM_ReloadCMailMsg:
\r
5805 Reset(TRUE, TRUE);
\r
5806 ReloadCmailMsgEvent(FALSE);
\r
5809 case IDM_Minimize:
\r
5810 ShowWindow(hwnd, SW_MINIMIZE);
\r
5817 case IDM_MachineWhite:
\r
5818 MachineWhiteEvent();
\r
5820 * refresh the tags dialog only if it's visible
\r
5822 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5824 tags = PGNTags(&gameInfo);
\r
5825 TagsPopUp(tags, CmailMsg());
\r
5828 SAY("computer starts playing white");
\r
5831 case IDM_MachineBlack:
\r
5832 MachineBlackEvent();
\r
5834 * refresh the tags dialog only if it's visible
\r
5836 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5838 tags = PGNTags(&gameInfo);
\r
5839 TagsPopUp(tags, CmailMsg());
\r
5842 SAY("computer starts playing black");
\r
5845 case IDM_TwoMachines:
\r
5846 TwoMachinesEvent();
\r
5848 * refresh the tags dialog only if it's visible
\r
5850 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5852 tags = PGNTags(&gameInfo);
\r
5853 TagsPopUp(tags, CmailMsg());
\r
5856 SAY("programs start playing each other");
\r
5859 case IDM_AnalysisMode:
\r
5860 if (!first.analysisSupport) {
\r
5861 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5862 DisplayError(buf, 0);
\r
5864 SAY("analyzing current position");
\r
5865 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5866 if (appData.icsActive) {
\r
5867 if (gameMode != IcsObserving) {
\r
5868 sprintf(buf, "You are not observing a game");
\r
5869 DisplayError(buf, 0);
\r
5870 /* secure check */
\r
5871 if (appData.icsEngineAnalyze) {
\r
5872 if (appData.debugMode)
\r
5873 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5874 ExitAnalyzeMode();
\r
5880 /* if enable, user want disable icsEngineAnalyze */
\r
5881 if (appData.icsEngineAnalyze) {
\r
5882 ExitAnalyzeMode();
\r
5886 appData.icsEngineAnalyze = TRUE;
\r
5887 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5890 if (!appData.showThinking) ToggleShowThinking();
\r
5891 AnalyzeModeEvent();
\r
5895 case IDM_AnalyzeFile:
\r
5896 if (!first.analysisSupport) {
\r
5897 char buf[MSG_SIZ];
\r
5898 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5899 DisplayError(buf, 0);
\r
5901 if (!appData.showThinking) ToggleShowThinking();
\r
5902 AnalyzeFileEvent();
\r
5903 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5904 AnalysisPeriodicEvent(1);
\r
5908 case IDM_IcsClient:
\r
5912 case IDM_EditGame:
\r
5917 case IDM_EditPosition:
\r
5918 EditPositionEvent();
\r
5919 SAY("to set up a position type a FEN");
\r
5922 case IDM_Training:
\r
5926 case IDM_ShowGameList:
\r
5927 ShowGameListProc();
\r
5930 case IDM_EditTags:
\r
5934 case IDM_EditComment:
\r
5935 if (commentDialogUp && editComment) {
\r
5938 EditCommentEvent();
\r
5958 case IDM_CallFlag:
\r
5978 case IDM_StopObserving:
\r
5979 StopObservingEvent();
\r
5982 case IDM_StopExamining:
\r
5983 StopExaminingEvent();
\r
5986 case IDM_TypeInMove:
\r
5987 PopUpMoveDialog('\000');
\r
5990 case IDM_TypeInName:
\r
5991 PopUpNameDialog('\000');
\r
5994 case IDM_Backward:
\r
5996 SetFocus(hwndMain);
\r
6003 SetFocus(hwndMain);
\r
6008 SetFocus(hwndMain);
\r
6013 SetFocus(hwndMain);
\r
6020 case IDM_TruncateGame:
\r
6021 TruncateGameEvent();
\r
6028 case IDM_RetractMove:
\r
6029 RetractMoveEvent();
\r
6032 case IDM_FlipView:
\r
6033 flipView = !flipView;
\r
6034 DrawPosition(FALSE, NULL);
\r
6037 case IDM_FlipClock:
\r
6038 flipClock = !flipClock;
\r
6039 DisplayBothClocks();
\r
6040 DrawPosition(FALSE, NULL);
\r
6043 case IDM_MuteSounds:
\r
6044 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6045 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6046 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6049 case IDM_GeneralOptions:
\r
6050 GeneralOptionsPopup(hwnd);
\r
6051 DrawPosition(TRUE, NULL);
\r
6054 case IDM_BoardOptions:
\r
6055 BoardOptionsPopup(hwnd);
\r
6058 case IDM_EnginePlayOptions:
\r
6059 EnginePlayOptionsPopup(hwnd);
\r
6062 case IDM_Engine1Options:
\r
6063 EngineOptionsPopup(hwnd, &first);
\r
6066 case IDM_Engine2Options:
\r
6067 EngineOptionsPopup(hwnd, &second);
\r
6070 case IDM_OptionsUCI:
\r
6071 UciOptionsPopup(hwnd);
\r
6074 case IDM_IcsOptions:
\r
6075 IcsOptionsPopup(hwnd);
\r
6079 FontsOptionsPopup(hwnd);
\r
6083 SoundOptionsPopup(hwnd);
\r
6086 case IDM_CommPort:
\r
6087 CommPortOptionsPopup(hwnd);
\r
6090 case IDM_LoadOptions:
\r
6091 LoadOptionsPopup(hwnd);
\r
6094 case IDM_SaveOptions:
\r
6095 SaveOptionsPopup(hwnd);
\r
6098 case IDM_TimeControl:
\r
6099 TimeControlOptionsPopup(hwnd);
\r
6102 case IDM_SaveSettings:
\r
6103 SaveSettings(settingsFileName);
\r
6106 case IDM_SaveSettingsOnExit:
\r
6107 saveSettingsOnExit = !saveSettingsOnExit;
\r
6108 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6109 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6110 MF_CHECKED : MF_UNCHECKED));
\r
6121 case IDM_AboutGame:
\r
6126 appData.debugMode = !appData.debugMode;
\r
6127 if (appData.debugMode) {
\r
6128 char dir[MSG_SIZ];
\r
6129 GetCurrentDirectory(MSG_SIZ, dir);
\r
6130 SetCurrentDirectory(installDir);
\r
6131 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6132 SetCurrentDirectory(dir);
\r
6133 setbuf(debugFP, NULL);
\r
6140 case IDM_HELPCONTENTS:
\r
6141 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6142 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6143 MessageBox (GetFocus(),
\r
6144 "Unable to activate help",
\r
6145 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6149 case IDM_HELPSEARCH:
\r
6150 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6151 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6152 MessageBox (GetFocus(),
\r
6153 "Unable to activate help",
\r
6154 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6158 case IDM_HELPHELP:
\r
6159 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6160 MessageBox (GetFocus(),
\r
6161 "Unable to activate help",
\r
6162 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6167 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6169 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6170 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6171 FreeProcInstance(lpProc);
\r
6174 case IDM_DirectCommand1:
\r
6175 AskQuestionEvent("Direct Command",
\r
6176 "Send to chess program:", "", "1");
\r
6178 case IDM_DirectCommand2:
\r
6179 AskQuestionEvent("Direct Command",
\r
6180 "Send to second chess program:", "", "2");
\r
6183 case EP_WhitePawn:
\r
6184 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6185 fromX = fromY = -1;
\r
6188 case EP_WhiteKnight:
\r
6189 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6190 fromX = fromY = -1;
\r
6193 case EP_WhiteBishop:
\r
6194 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6195 fromX = fromY = -1;
\r
6198 case EP_WhiteRook:
\r
6199 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6200 fromX = fromY = -1;
\r
6203 case EP_WhiteQueen:
\r
6204 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6205 fromX = fromY = -1;
\r
6208 case EP_WhiteFerz:
\r
6209 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6210 fromX = fromY = -1;
\r
6213 case EP_WhiteWazir:
\r
6214 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6215 fromX = fromY = -1;
\r
6218 case EP_WhiteAlfil:
\r
6219 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6220 fromX = fromY = -1;
\r
6223 case EP_WhiteCannon:
\r
6224 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6225 fromX = fromY = -1;
\r
6228 case EP_WhiteCardinal:
\r
6229 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6230 fromX = fromY = -1;
\r
6233 case EP_WhiteMarshall:
\r
6234 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6235 fromX = fromY = -1;
\r
6238 case EP_WhiteKing:
\r
6239 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6240 fromX = fromY = -1;
\r
6243 case EP_BlackPawn:
\r
6244 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6245 fromX = fromY = -1;
\r
6248 case EP_BlackKnight:
\r
6249 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_BlackBishop:
\r
6254 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_BlackRook:
\r
6259 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_BlackQueen:
\r
6264 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_BlackFerz:
\r
6269 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_BlackWazir:
\r
6274 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_BlackAlfil:
\r
6279 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_BlackCannon:
\r
6284 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_BlackCardinal:
\r
6289 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_BlackMarshall:
\r
6294 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_BlackKing:
\r
6299 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_EmptySquare:
\r
6304 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_ClearBoard:
\r
6309 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6314 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6319 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6324 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6329 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6334 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6339 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6344 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6349 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6354 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6359 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6365 case CLOCK_TIMER_ID:
\r
6366 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6367 clockTimerEvent = 0;
\r
6368 DecrementClocks(); /* call into back end */
\r
6370 case LOAD_GAME_TIMER_ID:
\r
6371 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6372 loadGameTimerEvent = 0;
\r
6373 AutoPlayGameLoop(); /* call into back end */
\r
6375 case ANALYSIS_TIMER_ID:
\r
6376 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6377 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6378 AnalysisPeriodicEvent(0);
\r
6380 KillTimer(hwnd, analysisTimerEvent);
\r
6381 analysisTimerEvent = 0;
\r
6384 case DELAYED_TIMER_ID:
\r
6385 KillTimer(hwnd, delayedTimerEvent);
\r
6386 delayedTimerEvent = 0;
\r
6387 delayedTimerCallback();
\r
6392 case WM_USER_Input:
\r
6393 InputEvent(hwnd, message, wParam, lParam);
\r
6396 /* [AS] Also move "attached" child windows */
\r
6397 case WM_WINDOWPOSCHANGING:
\r
6399 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6400 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6402 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6403 /* Window is moving */
\r
6406 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6407 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6408 rcMain.right = boardX + winWidth;
\r
6409 rcMain.top = boardY;
\r
6410 rcMain.bottom = boardY + winHeight;
\r
6412 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6413 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6414 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6415 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6416 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6423 /* [AS] Snapping */
\r
6424 case WM_ENTERSIZEMOVE:
\r
6425 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6426 if (hwnd == hwndMain) {
\r
6427 doingSizing = TRUE;
\r
6430 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6434 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6435 if (hwnd == hwndMain) {
\r
6436 lastSizing = wParam;
\r
6441 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6442 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6444 case WM_EXITSIZEMOVE:
\r
6445 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6446 if (hwnd == hwndMain) {
\r
6448 doingSizing = FALSE;
\r
6449 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6450 GetClientRect(hwnd, &client);
\r
6451 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6453 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6455 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6458 case WM_DESTROY: /* message: window being destroyed */
\r
6459 PostQuitMessage(0);
\r
6463 if (hwnd == hwndMain) {
\r
6468 default: /* Passes it on if unprocessed */
\r
6469 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6474 /*---------------------------------------------------------------------------*\
\r
6476 * Misc utility routines
\r
6478 \*---------------------------------------------------------------------------*/
\r
6481 * Decent random number generator, at least not as bad as Windows
\r
6482 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6484 unsigned int randstate;
\r
6489 randstate = randstate * 1664525 + 1013904223;
\r
6490 return (int) randstate & 0x7fffffff;
\r
6494 mysrandom(unsigned int seed)
\r
6501 * returns TRUE if user selects a different color, FALSE otherwise
\r
6505 ChangeColor(HWND hwnd, COLORREF *which)
\r
6507 static BOOL firstTime = TRUE;
\r
6508 static DWORD customColors[16];
\r
6510 COLORREF newcolor;
\r
6515 /* Make initial colors in use available as custom colors */
\r
6516 /* Should we put the compiled-in defaults here instead? */
\r
6518 customColors[i++] = lightSquareColor & 0xffffff;
\r
6519 customColors[i++] = darkSquareColor & 0xffffff;
\r
6520 customColors[i++] = whitePieceColor & 0xffffff;
\r
6521 customColors[i++] = blackPieceColor & 0xffffff;
\r
6522 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6523 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6525 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6526 customColors[i++] = textAttribs[ccl].color;
\r
6528 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6529 firstTime = FALSE;
\r
6532 cc.lStructSize = sizeof(cc);
\r
6533 cc.hwndOwner = hwnd;
\r
6534 cc.hInstance = NULL;
\r
6535 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6536 cc.lpCustColors = (LPDWORD) customColors;
\r
6537 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6539 if (!ChooseColor(&cc)) return FALSE;
\r
6541 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6542 if (newcolor == *which) return FALSE;
\r
6543 *which = newcolor;
\r
6547 InitDrawingColors();
\r
6548 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6553 MyLoadSound(MySound *ms)
\r
6559 if (ms->data) free(ms->data);
\r
6562 switch (ms->name[0]) {
\r
6568 /* System sound from Control Panel. Don't preload here. */
\r
6572 if (ms->name[1] == NULLCHAR) {
\r
6573 /* "!" alone = silence */
\r
6576 /* Builtin wave resource. Error if not found. */
\r
6577 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6578 if (h == NULL) break;
\r
6579 ms->data = (void *)LoadResource(hInst, h);
\r
6580 if (h == NULL) break;
\r
6585 /* .wav file. Error if not found. */
\r
6586 f = fopen(ms->name, "rb");
\r
6587 if (f == NULL) break;
\r
6588 if (fstat(fileno(f), &st) < 0) break;
\r
6589 ms->data = malloc(st.st_size);
\r
6590 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6596 char buf[MSG_SIZ];
\r
6597 sprintf(buf, "Error loading sound %s", ms->name);
\r
6598 DisplayError(buf, GetLastError());
\r
6604 MyPlaySound(MySound *ms)
\r
6606 BOOLEAN ok = FALSE;
\r
6608 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6609 switch (ms->name[0]) {
\r
6611 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6616 /* System sound from Control Panel (deprecated feature).
\r
6617 "$" alone or an unset sound name gets default beep (still in use). */
\r
6618 if (ms->name[1]) {
\r
6619 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6621 if (!ok) ok = MessageBeep(MB_OK);
\r
6624 /* Builtin wave resource, or "!" alone for silence */
\r
6625 if (ms->name[1]) {
\r
6626 if (ms->data == NULL) return FALSE;
\r
6627 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6633 /* .wav file. Error if not found. */
\r
6634 if (ms->data == NULL) return FALSE;
\r
6635 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6638 /* Don't print an error: this can happen innocently if the sound driver
\r
6639 is busy; for instance, if another instance of WinBoard is playing
\r
6640 a sound at about the same time. */
\r
6646 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6649 OPENFILENAME *ofn;
\r
6650 static UINT *number; /* gross that this is static */
\r
6652 switch (message) {
\r
6653 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6654 /* Center the dialog over the application window */
\r
6655 ofn = (OPENFILENAME *) lParam;
\r
6656 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6657 number = (UINT *) ofn->lCustData;
\r
6658 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6662 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6663 return FALSE; /* Allow for further processing */
\r
6666 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6667 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6669 return FALSE; /* Allow for further processing */
\r
6675 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6677 static UINT *number;
\r
6678 OPENFILENAME *ofname;
\r
6681 case WM_INITDIALOG:
\r
6682 ofname = (OPENFILENAME *)lParam;
\r
6683 number = (UINT *)(ofname->lCustData);
\r
6686 ofnot = (OFNOTIFY *)lParam;
\r
6687 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6688 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6697 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6698 char *nameFilt, char *dlgTitle, UINT *number,
\r
6699 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6701 OPENFILENAME openFileName;
\r
6702 char buf1[MSG_SIZ];
\r
6705 if (fileName == NULL) fileName = buf1;
\r
6706 if (defName == NULL) {
\r
6707 strcpy(fileName, "*.");
\r
6708 strcat(fileName, defExt);
\r
6710 strcpy(fileName, defName);
\r
6712 if (fileTitle) strcpy(fileTitle, "");
\r
6713 if (number) *number = 0;
\r
6715 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6716 openFileName.hwndOwner = hwnd;
\r
6717 openFileName.hInstance = (HANDLE) hInst;
\r
6718 openFileName.lpstrFilter = nameFilt;
\r
6719 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6720 openFileName.nMaxCustFilter = 0L;
\r
6721 openFileName.nFilterIndex = 1L;
\r
6722 openFileName.lpstrFile = fileName;
\r
6723 openFileName.nMaxFile = MSG_SIZ;
\r
6724 openFileName.lpstrFileTitle = fileTitle;
\r
6725 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6726 openFileName.lpstrInitialDir = NULL;
\r
6727 openFileName.lpstrTitle = dlgTitle;
\r
6728 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6729 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6730 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6731 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6732 openFileName.nFileOffset = 0;
\r
6733 openFileName.nFileExtension = 0;
\r
6734 openFileName.lpstrDefExt = defExt;
\r
6735 openFileName.lCustData = (LONG) number;
\r
6736 openFileName.lpfnHook = oldDialog ?
\r
6737 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6738 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6740 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6741 GetOpenFileName(&openFileName)) {
\r
6742 /* open the file */
\r
6743 f = fopen(openFileName.lpstrFile, write);
\r
6745 MessageBox(hwnd, "File open failed", NULL,
\r
6746 MB_OK|MB_ICONEXCLAMATION);
\r
6750 int err = CommDlgExtendedError();
\r
6751 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6760 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6762 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6765 * Get the first pop-up menu in the menu template. This is the
\r
6766 * menu that TrackPopupMenu displays.
\r
6768 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6770 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6773 * TrackPopup uses screen coordinates, so convert the
\r
6774 * coordinates of the mouse click to screen coordinates.
\r
6776 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6778 /* Draw and track the floating pop-up menu. */
\r
6779 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6780 pt.x, pt.y, 0, hwnd, NULL);
\r
6782 /* Destroy the menu.*/
\r
6783 DestroyMenu(hmenu);
\r
6788 int sizeX, sizeY, newSizeX, newSizeY;
\r
6790 } ResizeEditPlusButtonsClosure;
\r
6793 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6795 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6799 if (hChild == cl->hText) return TRUE;
\r
6800 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6801 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6802 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6803 ScreenToClient(cl->hDlg, &pt);
\r
6804 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6805 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6809 /* Resize a dialog that has a (rich) edit field filling most of
\r
6810 the top, with a row of buttons below */
\r
6812 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6815 int newTextHeight, newTextWidth;
\r
6816 ResizeEditPlusButtonsClosure cl;
\r
6818 /*if (IsIconic(hDlg)) return;*/
\r
6819 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6821 cl.hdwp = BeginDeferWindowPos(8);
\r
6823 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6824 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6825 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6826 if (newTextHeight < 0) {
\r
6827 newSizeY += -newTextHeight;
\r
6828 newTextHeight = 0;
\r
6830 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6831 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6837 cl.newSizeX = newSizeX;
\r
6838 cl.newSizeY = newSizeY;
\r
6839 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6841 EndDeferWindowPos(cl.hdwp);
\r
6844 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6846 RECT rChild, rParent;
\r
6847 int wChild, hChild, wParent, hParent;
\r
6848 int wScreen, hScreen, xNew, yNew;
\r
6851 /* Get the Height and Width of the child window */
\r
6852 GetWindowRect (hwndChild, &rChild);
\r
6853 wChild = rChild.right - rChild.left;
\r
6854 hChild = rChild.bottom - rChild.top;
\r
6856 /* Get the Height and Width of the parent window */
\r
6857 GetWindowRect (hwndParent, &rParent);
\r
6858 wParent = rParent.right - rParent.left;
\r
6859 hParent = rParent.bottom - rParent.top;
\r
6861 /* Get the display limits */
\r
6862 hdc = GetDC (hwndChild);
\r
6863 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6864 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6865 ReleaseDC(hwndChild, hdc);
\r
6867 /* Calculate new X position, then adjust for screen */
\r
6868 xNew = rParent.left + ((wParent - wChild) /2);
\r
6871 } else if ((xNew+wChild) > wScreen) {
\r
6872 xNew = wScreen - wChild;
\r
6875 /* Calculate new Y position, then adjust for screen */
\r
6877 yNew = rParent.top + ((hParent - hChild) /2);
\r
6880 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6885 } else if ((yNew+hChild) > hScreen) {
\r
6886 yNew = hScreen - hChild;
\r
6889 /* Set it, and return */
\r
6890 return SetWindowPos (hwndChild, NULL,
\r
6891 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6894 /* Center one window over another */
\r
6895 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6897 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6900 /*---------------------------------------------------------------------------*\
\r
6902 * Startup Dialog functions
\r
6904 \*---------------------------------------------------------------------------*/
\r
6906 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6908 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6910 while (*cd != NULL) {
\r
6911 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6917 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6919 char buf1[ARG_MAX];
\r
6922 if (str[0] == '@') {
\r
6923 FILE* f = fopen(str + 1, "r");
\r
6925 DisplayFatalError(str + 1, errno, 2);
\r
6928 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6930 buf1[len] = NULLCHAR;
\r
6934 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6937 char buf[MSG_SIZ];
\r
6938 char *end = strchr(str, '\n');
\r
6939 if (end == NULL) return;
\r
6940 memcpy(buf, str, end - str);
\r
6941 buf[end - str] = NULLCHAR;
\r
6942 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6948 SetStartupDialogEnables(HWND hDlg)
\r
6950 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6951 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6952 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6953 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6954 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6955 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6956 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6957 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6958 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6959 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6960 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6961 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6962 IsDlgButtonChecked(hDlg, OPT_View));
\r
6966 QuoteForFilename(char *filename)
\r
6968 int dquote, space;
\r
6969 dquote = strchr(filename, '"') != NULL;
\r
6970 space = strchr(filename, ' ') != NULL;
\r
6971 if (dquote || space) {
\r
6983 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6985 char buf[MSG_SIZ];
\r
6988 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6989 q = QuoteForFilename(nthcp);
\r
6990 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6991 if (*nthdir != NULLCHAR) {
\r
6992 q = QuoteForFilename(nthdir);
\r
6993 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6995 if (*nthcp == NULLCHAR) {
\r
6996 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6997 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6998 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6999 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7004 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7006 char buf[MSG_SIZ];
\r
7010 switch (message) {
\r
7011 case WM_INITDIALOG:
\r
7012 /* Center the dialog */
\r
7013 CenterWindow (hDlg, GetDesktopWindow());
\r
7014 /* Initialize the dialog items */
\r
7015 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7016 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7017 firstChessProgramNames);
\r
7018 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7019 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7020 secondChessProgramNames);
\r
7021 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7022 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7023 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7024 if (*appData.icsHelper != NULLCHAR) {
\r
7025 char *q = QuoteForFilename(appData.icsHelper);
\r
7026 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7028 if (*appData.icsHost == NULLCHAR) {
\r
7029 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7030 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7031 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7032 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7033 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7036 if (appData.icsActive) {
\r
7037 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7039 else if (appData.noChessProgram) {
\r
7040 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7043 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7046 SetStartupDialogEnables(hDlg);
\r
7050 switch (LOWORD(wParam)) {
\r
7052 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7053 strcpy(buf, "/fcp=");
\r
7054 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7056 ParseArgs(StringGet, &p);
\r
7057 strcpy(buf, "/scp=");
\r
7058 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7060 ParseArgs(StringGet, &p);
\r
7061 appData.noChessProgram = FALSE;
\r
7062 appData.icsActive = FALSE;
\r
7063 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7064 strcpy(buf, "/ics /icshost=");
\r
7065 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7067 ParseArgs(StringGet, &p);
\r
7068 if (appData.zippyPlay) {
\r
7069 strcpy(buf, "/fcp=");
\r
7070 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7072 ParseArgs(StringGet, &p);
\r
7074 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7075 appData.noChessProgram = TRUE;
\r
7076 appData.icsActive = FALSE;
\r
7078 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7079 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7082 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7083 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7085 ParseArgs(StringGet, &p);
\r
7087 EndDialog(hDlg, TRUE);
\r
7094 case IDM_HELPCONTENTS:
\r
7095 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7096 MessageBox (GetFocus(),
\r
7097 "Unable to activate help",
\r
7098 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7103 SetStartupDialogEnables(hDlg);
\r
7111 /*---------------------------------------------------------------------------*\
\r
7113 * About box dialog functions
\r
7115 \*---------------------------------------------------------------------------*/
\r
7117 /* Process messages for "About" dialog box */
\r
7119 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7121 switch (message) {
\r
7122 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7123 /* Center the dialog over the application window */
\r
7124 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7125 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7129 case WM_COMMAND: /* message: received a command */
\r
7130 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7131 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7132 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7140 /*---------------------------------------------------------------------------*\
\r
7142 * Comment Dialog functions
\r
7144 \*---------------------------------------------------------------------------*/
\r
7147 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7149 static HANDLE hwndText = NULL;
\r
7150 int len, newSizeX, newSizeY, flags;
\r
7151 static int sizeX, sizeY;
\r
7156 switch (message) {
\r
7157 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7158 /* Initialize the dialog items */
\r
7159 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7160 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7161 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7162 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7163 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7164 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7165 SetWindowText(hDlg, commentTitle);
\r
7166 if (editComment) {
\r
7167 SetFocus(hwndText);
\r
7169 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7171 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7172 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7173 MAKELPARAM(FALSE, 0));
\r
7174 /* Size and position the dialog */
\r
7175 if (!commentDialog) {
\r
7176 commentDialog = hDlg;
\r
7177 flags = SWP_NOZORDER;
\r
7178 GetClientRect(hDlg, &rect);
\r
7179 sizeX = rect.right;
\r
7180 sizeY = rect.bottom;
\r
7181 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7182 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7183 WINDOWPLACEMENT wp;
\r
7184 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7185 wp.length = sizeof(WINDOWPLACEMENT);
\r
7187 wp.showCmd = SW_SHOW;
\r
7188 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7189 wp.rcNormalPosition.left = commentX;
\r
7190 wp.rcNormalPosition.right = commentX + commentW;
\r
7191 wp.rcNormalPosition.top = commentY;
\r
7192 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7193 SetWindowPlacement(hDlg, &wp);
\r
7195 GetClientRect(hDlg, &rect);
\r
7196 newSizeX = rect.right;
\r
7197 newSizeY = rect.bottom;
\r
7198 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7199 newSizeX, newSizeY);
\r
7206 case WM_COMMAND: /* message: received a command */
\r
7207 switch (LOWORD(wParam)) {
\r
7209 if (editComment) {
\r
7211 /* Read changed options from the dialog box */
\r
7212 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7213 len = GetWindowTextLength(hwndText);
\r
7214 str = (char *) malloc(len + 1);
\r
7215 GetWindowText(hwndText, str, len + 1);
\r
7224 ReplaceComment(commentIndex, str);
\r
7231 case OPT_CancelComment:
\r
7235 case OPT_ClearComment:
\r
7236 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7239 case OPT_EditComment:
\r
7240 EditCommentEvent();
\r
7249 newSizeX = LOWORD(lParam);
\r
7250 newSizeY = HIWORD(lParam);
\r
7251 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7256 case WM_GETMINMAXINFO:
\r
7257 /* Prevent resizing window too small */
\r
7258 mmi = (MINMAXINFO *) lParam;
\r
7259 mmi->ptMinTrackSize.x = 100;
\r
7260 mmi->ptMinTrackSize.y = 100;
\r
7267 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7272 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7274 if (str == NULL) str = "";
\r
7275 p = (char *) malloc(2 * strlen(str) + 2);
\r
7278 if (*str == '\n') *q++ = '\r';
\r
7282 if (commentText != NULL) free(commentText);
\r
7284 commentIndex = index;
\r
7285 commentTitle = title;
\r
7287 editComment = edit;
\r
7289 if (commentDialog) {
\r
7290 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7291 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7293 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7294 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7295 hwndMain, (DLGPROC)lpProc);
\r
7296 FreeProcInstance(lpProc);
\r
7298 commentDialogUp = TRUE;
\r
7302 /*---------------------------------------------------------------------------*\
\r
7304 * Type-in move dialog functions
\r
7306 \*---------------------------------------------------------------------------*/
\r
7309 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7311 char move[MSG_SIZ];
\r
7313 ChessMove moveType;
\r
7314 int fromX, fromY, toX, toY;
\r
7317 switch (message) {
\r
7318 case WM_INITDIALOG:
\r
7319 move[0] = (char) lParam;
\r
7320 move[1] = NULLCHAR;
\r
7321 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7322 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7323 SetWindowText(hInput, move);
\r
7325 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7329 switch (LOWORD(wParam)) {
\r
7331 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7332 { int n; Board board;
\r
7334 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7335 EditPositionPasteFEN(move);
\r
7336 EndDialog(hDlg, TRUE);
\r
7339 // [HGM] movenum: allow move number to be typed in any mode
\r
7340 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7341 currentMove = 2*n-1;
\r
7342 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7343 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7344 EndDialog(hDlg, TRUE);
\r
7345 DrawPosition(TRUE, boards[currentMove]);
\r
7346 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7347 else DisplayMessage("", "");
\r
7351 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7352 gameMode != Training) {
\r
7353 DisplayMoveError("Displayed move is not current");
\r
7355 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7356 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7357 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7358 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7359 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7360 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7361 if (gameMode != Training)
\r
7362 forwardMostMove = currentMove;
\r
7363 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7365 DisplayMoveError("Could not parse move");
\r
7368 EndDialog(hDlg, TRUE);
\r
7371 EndDialog(hDlg, FALSE);
\r
7382 PopUpMoveDialog(char firstchar)
\r
7386 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7387 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7388 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7389 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7390 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7391 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7392 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7393 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7394 gameMode == Training) {
\r
7395 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7396 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7397 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7398 FreeProcInstance(lpProc);
\r
7402 /*---------------------------------------------------------------------------*\
\r
7404 * Type-in name dialog functions
\r
7406 \*---------------------------------------------------------------------------*/
\r
7409 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7411 char move[MSG_SIZ];
\r
7414 switch (message) {
\r
7415 case WM_INITDIALOG:
\r
7416 move[0] = (char) lParam;
\r
7417 move[1] = NULLCHAR;
\r
7418 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7419 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7420 SetWindowText(hInput, move);
\r
7422 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7426 switch (LOWORD(wParam)) {
\r
7428 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7429 appData.userName = strdup(move);
\r
7432 EndDialog(hDlg, TRUE);
\r
7435 EndDialog(hDlg, FALSE);
\r
7446 PopUpNameDialog(char firstchar)
\r
7450 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7451 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7452 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7453 FreeProcInstance(lpProc);
\r
7456 /*---------------------------------------------------------------------------*\
\r
7460 \*---------------------------------------------------------------------------*/
\r
7462 /* Nonmodal error box */
\r
7463 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7464 WPARAM wParam, LPARAM lParam);
\r
7467 ErrorPopUp(char *title, char *content)
\r
7471 BOOLEAN modal = hwndMain == NULL;
\r
7489 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7490 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7493 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7495 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7496 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7497 hwndMain, (DLGPROC)lpProc);
\r
7498 FreeProcInstance(lpProc);
\r
7505 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7506 if (errorDialog == NULL) return;
\r
7507 DestroyWindow(errorDialog);
\r
7508 errorDialog = NULL;
\r
7512 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7517 switch (message) {
\r
7518 case WM_INITDIALOG:
\r
7519 GetWindowRect(hDlg, &rChild);
\r
7522 SetWindowPos(hDlg, NULL, rChild.left,
\r
7523 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7524 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7528 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7529 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7530 and it doesn't work when you resize the dialog.
\r
7531 For now, just give it a default position.
\r
7533 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7535 errorDialog = hDlg;
\r
7536 SetWindowText(hDlg, errorTitle);
\r
7537 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7538 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7542 switch (LOWORD(wParam)) {
\r
7545 if (errorDialog == hDlg) errorDialog = NULL;
\r
7546 DestroyWindow(hDlg);
\r
7558 HWND gothicDialog = NULL;
\r
7561 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7565 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7567 switch (message) {
\r
7568 case WM_INITDIALOG:
\r
7569 GetWindowRect(hDlg, &rChild);
\r
7571 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7575 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7576 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7577 and it doesn't work when you resize the dialog.
\r
7578 For now, just give it a default position.
\r
7580 gothicDialog = hDlg;
\r
7581 SetWindowText(hDlg, errorTitle);
\r
7582 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7583 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7587 switch (LOWORD(wParam)) {
\r
7590 if (errorDialog == hDlg) errorDialog = NULL;
\r
7591 DestroyWindow(hDlg);
\r
7603 GothicPopUp(char *title, VariantClass variant)
\r
7606 static char *lastTitle;
\r
7608 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7609 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7611 if(lastTitle != title && gothicDialog != NULL) {
\r
7612 DestroyWindow(gothicDialog);
\r
7613 gothicDialog = NULL;
\r
7615 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7616 title = lastTitle;
\r
7617 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7618 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7619 hwndMain, (DLGPROC)lpProc);
\r
7620 FreeProcInstance(lpProc);
\r
7625 /*---------------------------------------------------------------------------*\
\r
7627 * Ics Interaction console functions
\r
7629 \*---------------------------------------------------------------------------*/
\r
7631 #define HISTORY_SIZE 64
\r
7632 static char *history[HISTORY_SIZE];
\r
7633 int histIn = 0, histP = 0;
\r
7636 SaveInHistory(char *cmd)
\r
7638 if (history[histIn] != NULL) {
\r
7639 free(history[histIn]);
\r
7640 history[histIn] = NULL;
\r
7642 if (*cmd == NULLCHAR) return;
\r
7643 history[histIn] = StrSave(cmd);
\r
7644 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7645 if (history[histIn] != NULL) {
\r
7646 free(history[histIn]);
\r
7647 history[histIn] = NULL;
\r
7653 PrevInHistory(char *cmd)
\r
7656 if (histP == histIn) {
\r
7657 if (history[histIn] != NULL) free(history[histIn]);
\r
7658 history[histIn] = StrSave(cmd);
\r
7660 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7661 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7663 return history[histP];
\r
7669 if (histP == histIn) return NULL;
\r
7670 histP = (histP + 1) % HISTORY_SIZE;
\r
7671 return history[histP];
\r
7678 BOOLEAN immediate;
\r
7679 } IcsTextMenuEntry;
\r
7680 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7681 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7684 ParseIcsTextMenu(char *icsTextMenuString)
\r
7687 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7688 char *p = icsTextMenuString;
\r
7689 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7692 if (e->command != NULL) {
\r
7694 e->command = NULL;
\r
7698 e = icsTextMenuEntry;
\r
7699 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7700 if (*p == ';' || *p == '\n') {
\r
7701 e->item = strdup("-");
\r
7702 e->command = NULL;
\r
7704 } else if (*p == '-') {
\r
7705 e->item = strdup("-");
\r
7706 e->command = NULL;
\r
7710 char *q, *r, *s, *t;
\r
7712 q = strchr(p, ',');
\r
7713 if (q == NULL) break;
\r
7715 r = strchr(q + 1, ',');
\r
7716 if (r == NULL) break;
\r
7718 s = strchr(r + 1, ',');
\r
7719 if (s == NULL) break;
\r
7722 t = strchr(s + 1, c);
\r
7725 t = strchr(s + 1, c);
\r
7727 if (t != NULL) *t = NULLCHAR;
\r
7728 e->item = strdup(p);
\r
7729 e->command = strdup(q + 1);
\r
7730 e->getname = *(r + 1) != '0';
\r
7731 e->immediate = *(s + 1) != '0';
\r
7735 if (t == NULL) break;
\r
7744 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7748 hmenu = LoadMenu(hInst, "TextMenu");
\r
7749 h = GetSubMenu(hmenu, 0);
\r
7751 if (strcmp(e->item, "-") == 0) {
\r
7752 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7754 if (e->item[0] == '|') {
\r
7755 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7756 IDM_CommandX + i, &e->item[1]);
\r
7758 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7767 WNDPROC consoleTextWindowProc;
\r
7770 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7772 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7773 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7777 SetWindowText(hInput, command);
\r
7779 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7781 sel.cpMin = 999999;
\r
7782 sel.cpMax = 999999;
\r
7783 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7788 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7789 if (sel.cpMin == sel.cpMax) {
\r
7790 /* Expand to surrounding word */
\r
7793 tr.chrg.cpMax = sel.cpMin;
\r
7794 tr.chrg.cpMin = --sel.cpMin;
\r
7795 if (sel.cpMin < 0) break;
\r
7796 tr.lpstrText = name;
\r
7797 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7798 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7802 tr.chrg.cpMin = sel.cpMax;
\r
7803 tr.chrg.cpMax = ++sel.cpMax;
\r
7804 tr.lpstrText = name;
\r
7805 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7806 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7809 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7810 MessageBeep(MB_ICONEXCLAMATION);
\r
7814 tr.lpstrText = name;
\r
7815 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7817 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7818 MessageBeep(MB_ICONEXCLAMATION);
\r
7821 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7824 sprintf(buf, "%s %s", command, name);
\r
7825 SetWindowText(hInput, buf);
\r
7826 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7828 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7829 SetWindowText(hInput, buf);
\r
7830 sel.cpMin = 999999;
\r
7831 sel.cpMax = 999999;
\r
7832 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7838 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7843 switch (message) {
\r
7845 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7848 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7851 sel.cpMin = 999999;
\r
7852 sel.cpMax = 999999;
\r
7853 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7854 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7859 if(wParam != '\022') {
\r
7860 if (wParam == '\t') {
\r
7861 if (GetKeyState(VK_SHIFT) < 0) {
\r
7863 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7864 if (buttonDesc[0].hwnd) {
\r
7865 SetFocus(buttonDesc[0].hwnd);
\r
7867 SetFocus(hwndMain);
\r
7871 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7874 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7875 JAWS_DELETE( SetFocus(hInput); )
\r
7876 SendMessage(hInput, message, wParam, lParam);
\r
7879 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7880 case WM_RBUTTONUP:
\r
7881 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7882 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7883 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7886 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7887 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7888 if (sel.cpMin == sel.cpMax) {
\r
7889 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7890 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7892 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7893 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7895 pt.x = LOWORD(lParam);
\r
7896 pt.y = HIWORD(lParam);
\r
7897 MenuPopup(hwnd, pt, hmenu, -1);
\r
7901 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7903 return SendMessage(hInput, message, wParam, lParam);
\r
7904 case WM_MBUTTONDOWN:
\r
7905 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7906 case WM_RBUTTONDOWN:
\r
7907 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7908 /* Move selection here if it was empty */
\r
7910 pt.x = LOWORD(lParam);
\r
7911 pt.y = HIWORD(lParam);
\r
7912 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7913 if (sel.cpMin == sel.cpMax) {
\r
7914 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7915 sel.cpMax = sel.cpMin;
\r
7916 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7918 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7922 switch (LOWORD(wParam)) {
\r
7923 case IDM_QuickPaste:
\r
7925 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7926 if (sel.cpMin == sel.cpMax) {
\r
7927 MessageBeep(MB_ICONEXCLAMATION);
\r
7930 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7931 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7932 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7937 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7940 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7943 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7947 int i = LOWORD(wParam) - IDM_CommandX;
\r
7948 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7949 icsTextMenuEntry[i].command != NULL) {
\r
7950 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7951 icsTextMenuEntry[i].getname,
\r
7952 icsTextMenuEntry[i].immediate);
\r
7960 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7963 WNDPROC consoleInputWindowProc;
\r
7966 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7968 char buf[MSG_SIZ];
\r
7970 static BOOL sendNextChar = FALSE;
\r
7971 static BOOL quoteNextChar = FALSE;
\r
7972 InputSource *is = consoleInputSource;
\r
7976 switch (message) {
\r
7978 if (!appData.localLineEditing || sendNextChar) {
\r
7979 is->buf[0] = (CHAR) wParam;
\r
7981 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7982 sendNextChar = FALSE;
\r
7985 if (quoteNextChar) {
\r
7986 buf[0] = (char) wParam;
\r
7987 buf[1] = NULLCHAR;
\r
7988 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7989 quoteNextChar = FALSE;
\r
7993 case '\r': /* Enter key */
\r
7994 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7995 if (consoleEcho) SaveInHistory(is->buf);
\r
7996 is->buf[is->count++] = '\n';
\r
7997 is->buf[is->count] = NULLCHAR;
\r
7998 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7999 if (consoleEcho) {
\r
8000 ConsoleOutput(is->buf, is->count, TRUE);
\r
8001 } else if (appData.localLineEditing) {
\r
8002 ConsoleOutput("\n", 1, TRUE);
\r
8005 case '\033': /* Escape key */
\r
8006 SetWindowText(hwnd, "");
\r
8007 cf.cbSize = sizeof(CHARFORMAT);
\r
8008 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8009 if (consoleEcho) {
\r
8010 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8012 cf.crTextColor = COLOR_ECHOOFF;
\r
8014 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8015 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8017 case '\t': /* Tab key */
\r
8018 if (GetKeyState(VK_SHIFT) < 0) {
\r
8020 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8023 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8024 if (buttonDesc[0].hwnd) {
\r
8025 SetFocus(buttonDesc[0].hwnd);
\r
8027 SetFocus(hwndMain);
\r
8031 case '\023': /* Ctrl+S */
\r
8032 sendNextChar = TRUE;
\r
8034 case '\021': /* Ctrl+Q */
\r
8035 quoteNextChar = TRUE;
\r
8045 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8046 p = PrevInHistory(buf);
\r
8048 SetWindowText(hwnd, p);
\r
8049 sel.cpMin = 999999;
\r
8050 sel.cpMax = 999999;
\r
8051 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8056 p = NextInHistory();
\r
8058 SetWindowText(hwnd, p);
\r
8059 sel.cpMin = 999999;
\r
8060 sel.cpMax = 999999;
\r
8061 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8067 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8071 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8075 case WM_MBUTTONDOWN:
\r
8076 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8077 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8079 case WM_RBUTTONUP:
\r
8080 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8081 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8082 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8086 hmenu = LoadMenu(hInst, "InputMenu");
\r
8087 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8088 if (sel.cpMin == sel.cpMax) {
\r
8089 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8090 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8092 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8093 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8095 pt.x = LOWORD(lParam);
\r
8096 pt.y = HIWORD(lParam);
\r
8097 MenuPopup(hwnd, pt, hmenu, -1);
\r
8101 switch (LOWORD(wParam)) {
\r
8103 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8105 case IDM_SelectAll:
\r
8107 sel.cpMax = -1; /*999999?*/
\r
8108 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8111 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8114 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8117 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8122 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8125 #define CO_MAX 100000
\r
8126 #define CO_TRIM 1000
\r
8129 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8131 static SnapData sd;
\r
8132 HWND hText, hInput;
\r
8134 static int sizeX, sizeY;
\r
8135 int newSizeX, newSizeY;
\r
8139 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8140 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8142 switch (message) {
\r
8144 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8146 ENLINK *pLink = (ENLINK*)lParam;
\r
8147 if (pLink->msg == WM_LBUTTONUP)
\r
8151 tr.chrg = pLink->chrg;
\r
8152 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8153 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8154 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8155 free(tr.lpstrText);
\r
8159 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8160 hwndConsole = hDlg;
\r
8162 consoleTextWindowProc = (WNDPROC)
\r
8163 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8164 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8165 consoleInputWindowProc = (WNDPROC)
\r
8166 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8167 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8168 Colorize(ColorNormal, TRUE);
\r
8169 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8170 ChangedConsoleFont();
\r
8171 GetClientRect(hDlg, &rect);
\r
8172 sizeX = rect.right;
\r
8173 sizeY = rect.bottom;
\r
8174 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8175 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8176 WINDOWPLACEMENT wp;
\r
8177 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8178 wp.length = sizeof(WINDOWPLACEMENT);
\r
8180 wp.showCmd = SW_SHOW;
\r
8181 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8182 wp.rcNormalPosition.left = wpConsole.x;
\r
8183 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8184 wp.rcNormalPosition.top = wpConsole.y;
\r
8185 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8186 SetWindowPlacement(hDlg, &wp);
\r
8189 // [HGM] Chessknight's change 2004-07-13
\r
8190 else { /* Determine Defaults */
\r
8191 WINDOWPLACEMENT wp;
\r
8192 wpConsole.x = winWidth + 1;
\r
8193 wpConsole.y = boardY;
\r
8194 wpConsole.width = screenWidth - winWidth;
\r
8195 wpConsole.height = winHeight;
\r
8196 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8197 wp.length = sizeof(WINDOWPLACEMENT);
\r
8199 wp.showCmd = SW_SHOW;
\r
8200 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8201 wp.rcNormalPosition.left = wpConsole.x;
\r
8202 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8203 wp.rcNormalPosition.top = wpConsole.y;
\r
8204 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8205 SetWindowPlacement(hDlg, &wp);
\r
8208 // Allow hText to highlight URLs and send notifications on them
\r
8209 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8210 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8211 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8212 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8226 if (IsIconic(hDlg)) break;
\r
8227 newSizeX = LOWORD(lParam);
\r
8228 newSizeY = HIWORD(lParam);
\r
8229 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8230 RECT rectText, rectInput;
\r
8232 int newTextHeight, newTextWidth;
\r
8233 GetWindowRect(hText, &rectText);
\r
8234 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8235 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8236 if (newTextHeight < 0) {
\r
8237 newSizeY += -newTextHeight;
\r
8238 newTextHeight = 0;
\r
8240 SetWindowPos(hText, NULL, 0, 0,
\r
8241 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8242 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8243 pt.x = rectInput.left;
\r
8244 pt.y = rectInput.top + newSizeY - sizeY;
\r
8245 ScreenToClient(hDlg, &pt);
\r
8246 SetWindowPos(hInput, NULL,
\r
8247 pt.x, pt.y, /* needs client coords */
\r
8248 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8249 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8255 case WM_GETMINMAXINFO:
\r
8256 /* Prevent resizing window too small */
\r
8257 mmi = (MINMAXINFO *) lParam;
\r
8258 mmi->ptMinTrackSize.x = 100;
\r
8259 mmi->ptMinTrackSize.y = 100;
\r
8262 /* [AS] Snapping */
\r
8263 case WM_ENTERSIZEMOVE:
\r
8264 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8267 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8270 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8272 case WM_EXITSIZEMOVE:
\r
8273 UpdateICSWidth(hText);
\r
8274 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8277 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8285 if (hwndConsole) return;
\r
8286 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8287 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8292 ConsoleOutput(char* data, int length, int forceVisible)
\r
8297 char buf[CO_MAX+1];
\r
8300 static int delayLF = 0;
\r
8301 CHARRANGE savesel, sel;
\r
8303 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8311 while (length--) {
\r
8319 } else if (*p == '\007') {
\r
8320 MyPlaySound(&sounds[(int)SoundBell]);
\r
8327 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8328 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8329 /* Save current selection */
\r
8330 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8331 exlen = GetWindowTextLength(hText);
\r
8332 /* Find out whether current end of text is visible */
\r
8333 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8334 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8335 /* Trim existing text if it's too long */
\r
8336 if (exlen + (q - buf) > CO_MAX) {
\r
8337 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8340 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8341 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8343 savesel.cpMin -= trim;
\r
8344 savesel.cpMax -= trim;
\r
8345 if (exlen < 0) exlen = 0;
\r
8346 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8347 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8349 /* Append the new text */
\r
8350 sel.cpMin = exlen;
\r
8351 sel.cpMax = exlen;
\r
8352 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8353 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8354 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8355 if (forceVisible || exlen == 0 ||
\r
8356 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8357 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8358 /* Scroll to make new end of text visible if old end of text
\r
8359 was visible or new text is an echo of user typein */
\r
8360 sel.cpMin = 9999999;
\r
8361 sel.cpMax = 9999999;
\r
8362 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8363 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8364 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8365 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8367 if (savesel.cpMax == exlen || forceVisible) {
\r
8368 /* Move insert point to new end of text if it was at the old
\r
8369 end of text or if the new text is an echo of user typein */
\r
8370 sel.cpMin = 9999999;
\r
8371 sel.cpMax = 9999999;
\r
8372 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8374 /* Restore previous selection */
\r
8375 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8377 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8384 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8388 COLORREF oldFg, oldBg;
\r
8392 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8394 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8395 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8396 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8399 rect.right = x + squareSize;
\r
8401 rect.bottom = y + squareSize;
\r
8404 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8405 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8406 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8407 &rect, str, strlen(str), NULL);
\r
8409 (void) SetTextColor(hdc, oldFg);
\r
8410 (void) SetBkColor(hdc, oldBg);
\r
8411 (void) SelectObject(hdc, oldFont);
\r
8415 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8416 RECT *rect, char *color, char *flagFell)
\r
8420 COLORREF oldFg, oldBg;
\r
8423 if (appData.clockMode) {
\r
8425 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8427 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8434 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8435 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8437 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8438 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8440 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8444 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8445 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8446 rect, str, strlen(str), NULL);
\r
8447 if(logoHeight > 0 && appData.clockMode) {
\r
8449 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8450 r.top = rect->top + logoHeight/2;
\r
8451 r.left = rect->left;
\r
8452 r.right = rect->right;
\r
8453 r.bottom = rect->bottom;
\r
8454 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8455 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8456 &r, str, strlen(str), NULL);
\r
8458 (void) SetTextColor(hdc, oldFg);
\r
8459 (void) SetBkColor(hdc, oldBg);
\r
8460 (void) SelectObject(hdc, oldFont);
\r
8465 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8471 if( count <= 0 ) {
\r
8472 if (appData.debugMode) {
\r
8473 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8476 return ERROR_INVALID_USER_BUFFER;
\r
8479 ResetEvent(ovl->hEvent);
\r
8480 ovl->Offset = ovl->OffsetHigh = 0;
\r
8481 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8485 err = GetLastError();
\r
8486 if (err == ERROR_IO_PENDING) {
\r
8487 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8491 err = GetLastError();
\r
8498 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8503 ResetEvent(ovl->hEvent);
\r
8504 ovl->Offset = ovl->OffsetHigh = 0;
\r
8505 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8509 err = GetLastError();
\r
8510 if (err == ERROR_IO_PENDING) {
\r
8511 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8515 err = GetLastError();
\r
8521 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8522 void CheckForInputBufferFull( InputSource * is )
\r
8524 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8525 /* Look for end of line */
\r
8526 char * p = is->buf;
\r
8528 while( p < is->next && *p != '\n' ) {
\r
8532 if( p >= is->next ) {
\r
8533 if (appData.debugMode) {
\r
8534 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8537 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8538 is->count = (DWORD) -1;
\r
8539 is->next = is->buf;
\r
8545 InputThread(LPVOID arg)
\r
8550 is = (InputSource *) arg;
\r
8551 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8552 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8553 while (is->hThread != NULL) {
\r
8554 is->error = DoReadFile(is->hFile, is->next,
\r
8555 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8556 &is->count, &ovl);
\r
8557 if (is->error == NO_ERROR) {
\r
8558 is->next += is->count;
\r
8560 if (is->error == ERROR_BROKEN_PIPE) {
\r
8561 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8564 is->count = (DWORD) -1;
\r
8565 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8570 CheckForInputBufferFull( is );
\r
8572 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8574 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8576 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8579 CloseHandle(ovl.hEvent);
\r
8580 CloseHandle(is->hFile);
\r
8582 if (appData.debugMode) {
\r
8583 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8590 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8592 NonOvlInputThread(LPVOID arg)
\r
8599 is = (InputSource *) arg;
\r
8600 while (is->hThread != NULL) {
\r
8601 is->error = ReadFile(is->hFile, is->next,
\r
8602 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8603 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8604 if (is->error == NO_ERROR) {
\r
8605 /* Change CRLF to LF */
\r
8606 if (is->next > is->buf) {
\r
8608 i = is->count + 1;
\r
8616 if (prev == '\r' && *p == '\n') {
\r
8628 if (is->error == ERROR_BROKEN_PIPE) {
\r
8629 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8632 is->count = (DWORD) -1;
\r
8636 CheckForInputBufferFull( is );
\r
8638 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8640 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8642 if (is->count < 0) break; /* Quit on error */
\r
8644 CloseHandle(is->hFile);
\r
8649 SocketInputThread(LPVOID arg)
\r
8653 is = (InputSource *) arg;
\r
8654 while (is->hThread != NULL) {
\r
8655 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8656 if ((int)is->count == SOCKET_ERROR) {
\r
8657 is->count = (DWORD) -1;
\r
8658 is->error = WSAGetLastError();
\r
8660 is->error = NO_ERROR;
\r
8661 is->next += is->count;
\r
8662 if (is->count == 0 && is->second == is) {
\r
8663 /* End of file on stderr; quit with no message */
\r
8667 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8669 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8671 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8677 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8681 is = (InputSource *) lParam;
\r
8682 if (is->lineByLine) {
\r
8683 /* Feed in lines one by one */
\r
8684 char *p = is->buf;
\r
8686 while (q < is->next) {
\r
8687 if (*q++ == '\n') {
\r
8688 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8693 /* Move any partial line to the start of the buffer */
\r
8695 while (p < is->next) {
\r
8700 if (is->error != NO_ERROR || is->count == 0) {
\r
8701 /* Notify backend of the error. Note: If there was a partial
\r
8702 line at the end, it is not flushed through. */
\r
8703 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8706 /* Feed in the whole chunk of input at once */
\r
8707 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8708 is->next = is->buf;
\r
8712 /*---------------------------------------------------------------------------*\
\r
8714 * Menu enables. Used when setting various modes.
\r
8716 \*---------------------------------------------------------------------------*/
\r
8724 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8726 while (enab->item > 0) {
\r
8727 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8732 Enables gnuEnables[] = {
\r
8733 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8734 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8735 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8736 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8737 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8738 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8739 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8740 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8742 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8747 Enables icsEnables[] = {
\r
8748 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8755 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8760 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8761 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8762 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8767 Enables zippyEnables[] = {
\r
8768 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8769 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8770 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8771 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8776 Enables ncpEnables[] = {
\r
8777 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8786 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8799 Enables trainingOnEnables[] = {
\r
8800 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8811 Enables trainingOffEnables[] = {
\r
8812 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8813 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8814 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8815 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8816 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8817 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8819 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8823 /* These modify either ncpEnables or gnuEnables */
\r
8824 Enables cmailEnables[] = {
\r
8825 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8826 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8827 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8828 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8830 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8835 Enables machineThinkingEnables[] = {
\r
8836 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8854 Enables userThinkingEnables[] = {
\r
8855 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8862 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8863 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8864 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8865 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8866 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8867 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8868 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8869 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8873 /*---------------------------------------------------------------------------*\
\r
8875 * Front-end interface functions exported by XBoard.
\r
8876 * Functions appear in same order as prototypes in frontend.h.
\r
8878 \*---------------------------------------------------------------------------*/
\r
8882 static UINT prevChecked = 0;
\r
8883 static int prevPausing = 0;
\r
8886 if (pausing != prevPausing) {
\r
8887 prevPausing = pausing;
\r
8888 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8889 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8890 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8893 switch (gameMode) {
\r
8894 case BeginningOfGame:
\r
8895 if (appData.icsActive)
\r
8896 nowChecked = IDM_IcsClient;
\r
8897 else if (appData.noChessProgram)
\r
8898 nowChecked = IDM_EditGame;
\r
8900 nowChecked = IDM_MachineBlack;
\r
8902 case MachinePlaysBlack:
\r
8903 nowChecked = IDM_MachineBlack;
\r
8905 case MachinePlaysWhite:
\r
8906 nowChecked = IDM_MachineWhite;
\r
8908 case TwoMachinesPlay:
\r
8909 nowChecked = IDM_TwoMachines;
\r
8912 nowChecked = IDM_AnalysisMode;
\r
8915 nowChecked = IDM_AnalyzeFile;
\r
8918 nowChecked = IDM_EditGame;
\r
8920 case PlayFromGameFile:
\r
8921 nowChecked = IDM_LoadGame;
\r
8923 case EditPosition:
\r
8924 nowChecked = IDM_EditPosition;
\r
8927 nowChecked = IDM_Training;
\r
8929 case IcsPlayingWhite:
\r
8930 case IcsPlayingBlack:
\r
8931 case IcsObserving:
\r
8933 nowChecked = IDM_IcsClient;
\r
8940 if (prevChecked != 0)
\r
8941 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8942 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8943 if (nowChecked != 0)
\r
8944 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8945 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8947 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8948 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8949 MF_BYCOMMAND|MF_ENABLED);
\r
8951 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8952 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8955 prevChecked = nowChecked;
\r
8957 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8958 if (appData.icsActive) {
\r
8959 if (appData.icsEngineAnalyze) {
\r
8960 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8961 MF_BYCOMMAND|MF_CHECKED);
\r
8963 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8964 MF_BYCOMMAND|MF_UNCHECKED);
\r
8972 HMENU hmenu = GetMenu(hwndMain);
\r
8973 SetMenuEnables(hmenu, icsEnables);
\r
8974 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8975 MF_BYPOSITION|MF_ENABLED);
\r
8977 if (appData.zippyPlay) {
\r
8978 SetMenuEnables(hmenu, zippyEnables);
\r
8979 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8980 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8981 MF_BYCOMMAND|MF_ENABLED);
\r
8989 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8995 HMENU hmenu = GetMenu(hwndMain);
\r
8996 SetMenuEnables(hmenu, ncpEnables);
\r
8997 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8998 MF_BYPOSITION|MF_GRAYED);
\r
8999 DrawMenuBar(hwndMain);
\r
9005 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9009 SetTrainingModeOn()
\r
9012 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9013 for (i = 0; i < N_BUTTONS; i++) {
\r
9014 if (buttonDesc[i].hwnd != NULL)
\r
9015 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9020 VOID SetTrainingModeOff()
\r
9023 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9024 for (i = 0; i < N_BUTTONS; i++) {
\r
9025 if (buttonDesc[i].hwnd != NULL)
\r
9026 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9032 SetUserThinkingEnables()
\r
9034 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9038 SetMachineThinkingEnables()
\r
9040 HMENU hMenu = GetMenu(hwndMain);
\r
9041 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9043 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9045 if (gameMode == MachinePlaysBlack) {
\r
9046 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9047 } else if (gameMode == MachinePlaysWhite) {
\r
9048 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9049 } else if (gameMode == TwoMachinesPlay) {
\r
9050 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9056 DisplayTitle(char *str)
\r
9058 char title[MSG_SIZ], *host;
\r
9059 if (str[0] != NULLCHAR) {
\r
9060 strcpy(title, str);
\r
9061 } else if (appData.icsActive) {
\r
9062 if (appData.icsCommPort[0] != NULLCHAR)
\r
9065 host = appData.icsHost;
\r
9066 sprintf(title, "%s: %s", szTitle, host);
\r
9067 } else if (appData.noChessProgram) {
\r
9068 strcpy(title, szTitle);
\r
9070 strcpy(title, szTitle);
\r
9071 strcat(title, ": ");
\r
9072 strcat(title, first.tidy);
\r
9074 SetWindowText(hwndMain, title);
\r
9079 DisplayMessage(char *str1, char *str2)
\r
9083 int remain = MESSAGE_TEXT_MAX - 1;
\r
9086 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9087 messageText[0] = NULLCHAR;
\r
9089 len = strlen(str1);
\r
9090 if (len > remain) len = remain;
\r
9091 strncpy(messageText, str1, len);
\r
9092 messageText[len] = NULLCHAR;
\r
9095 if (*str2 && remain >= 2) {
\r
9097 strcat(messageText, " ");
\r
9100 len = strlen(str2);
\r
9101 if (len > remain) len = remain;
\r
9102 strncat(messageText, str2, len);
\r
9104 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9106 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9110 hdc = GetDC(hwndMain);
\r
9111 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9112 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9113 &messageRect, messageText, strlen(messageText), NULL);
\r
9114 (void) SelectObject(hdc, oldFont);
\r
9115 (void) ReleaseDC(hwndMain, hdc);
\r
9119 DisplayError(char *str, int error)
\r
9121 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9127 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9128 NULL, error, LANG_NEUTRAL,
\r
9129 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9131 sprintf(buf, "%s:\n%s", str, buf2);
\r
9133 ErrorMap *em = errmap;
\r
9134 while (em->err != 0 && em->err != error) em++;
\r
9135 if (em->err != 0) {
\r
9136 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9138 sprintf(buf, "%s:\nError code %d", str, error);
\r
9143 ErrorPopUp("Error", buf);
\r
9148 DisplayMoveError(char *str)
\r
9150 fromX = fromY = -1;
\r
9151 ClearHighlights();
\r
9152 DrawPosition(FALSE, NULL);
\r
9153 if (appData.popupMoveErrors) {
\r
9154 ErrorPopUp("Error", str);
\r
9156 DisplayMessage(str, "");
\r
9157 moveErrorMessageUp = TRUE;
\r
9162 DisplayFatalError(char *str, int error, int exitStatus)
\r
9164 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9166 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9169 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9170 NULL, error, LANG_NEUTRAL,
\r
9171 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9173 sprintf(buf, "%s:\n%s", str, buf2);
\r
9175 ErrorMap *em = errmap;
\r
9176 while (em->err != 0 && em->err != error) em++;
\r
9177 if (em->err != 0) {
\r
9178 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9180 sprintf(buf, "%s:\nError code %d", str, error);
\r
9185 if (appData.debugMode) {
\r
9186 fprintf(debugFP, "%s: %s\n", label, str);
\r
9188 if (appData.popupExitMessage) {
\r
9189 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9190 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9192 ExitEvent(exitStatus);
\r
9197 DisplayInformation(char *str)
\r
9199 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9204 DisplayNote(char *str)
\r
9206 ErrorPopUp("Note", str);
\r
9211 char *title, *question, *replyPrefix;
\r
9216 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9218 static QuestionParams *qp;
\r
9219 char reply[MSG_SIZ];
\r
9222 switch (message) {
\r
9223 case WM_INITDIALOG:
\r
9224 qp = (QuestionParams *) lParam;
\r
9225 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9226 SetWindowText(hDlg, qp->title);
\r
9227 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9228 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9232 switch (LOWORD(wParam)) {
\r
9234 strcpy(reply, qp->replyPrefix);
\r
9235 if (*reply) strcat(reply, " ");
\r
9236 len = strlen(reply);
\r
9237 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9238 strcat(reply, "\n");
\r
9239 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9240 EndDialog(hDlg, TRUE);
\r
9241 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9244 EndDialog(hDlg, FALSE);
\r
9255 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9257 QuestionParams qp;
\r
9261 qp.question = question;
\r
9262 qp.replyPrefix = replyPrefix;
\r
9264 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9265 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9266 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9267 FreeProcInstance(lpProc);
\r
9270 /* [AS] Pick FRC position */
\r
9271 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9273 static int * lpIndexFRC;
\r
9279 case WM_INITDIALOG:
\r
9280 lpIndexFRC = (int *) lParam;
\r
9282 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9284 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9285 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9286 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9287 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9292 switch( LOWORD(wParam) ) {
\r
9294 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9295 EndDialog( hDlg, 0 );
\r
9296 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9299 EndDialog( hDlg, 1 );
\r
9301 case IDC_NFG_Edit:
\r
9302 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9303 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9305 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9308 case IDC_NFG_Random:
\r
9309 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9310 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9323 int index = appData.defaultFrcPosition;
\r
9324 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9326 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9328 if( result == 0 ) {
\r
9329 appData.defaultFrcPosition = index;
\r
9335 /* [AS] Game list options */
\r
9341 static GLT_Item GLT_ItemInfo[] = {
\r
9342 { GLT_EVENT, "Event" },
\r
9343 { GLT_SITE, "Site" },
\r
9344 { GLT_DATE, "Date" },
\r
9345 { GLT_ROUND, "Round" },
\r
9346 { GLT_PLAYERS, "Players" },
\r
9347 { GLT_RESULT, "Result" },
\r
9348 { GLT_WHITE_ELO, "White Rating" },
\r
9349 { GLT_BLACK_ELO, "Black Rating" },
\r
9350 { GLT_TIME_CONTROL,"Time Control" },
\r
9351 { GLT_VARIANT, "Variant" },
\r
9352 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9353 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9357 const char * GLT_FindItem( char id )
\r
9359 const char * result = 0;
\r
9361 GLT_Item * list = GLT_ItemInfo;
\r
9363 while( list->id != 0 ) {
\r
9364 if( list->id == id ) {
\r
9365 result = list->name;
\r
9375 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9377 const char * name = GLT_FindItem( id );
\r
9380 if( index >= 0 ) {
\r
9381 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9384 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9389 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9393 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9396 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9400 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9402 pc = GLT_ALL_TAGS;
\r
9405 if( strchr( tags, *pc ) == 0 ) {
\r
9406 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9411 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9414 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9416 char result = '\0';
\r
9419 GLT_Item * list = GLT_ItemInfo;
\r
9421 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9422 while( list->id != 0 ) {
\r
9423 if( strcmp( list->name, name ) == 0 ) {
\r
9424 result = list->id;
\r
9435 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9437 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9438 int idx2 = idx1 + delta;
\r
9439 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9441 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9444 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9445 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9446 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9447 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9451 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9453 static char glt[64];
\r
9454 static char * lpUserGLT;
\r
9458 case WM_INITDIALOG:
\r
9459 lpUserGLT = (char *) lParam;
\r
9461 strcpy( glt, lpUserGLT );
\r
9463 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9465 /* Initialize list */
\r
9466 GLT_TagsToList( hDlg, glt );
\r
9468 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9473 switch( LOWORD(wParam) ) {
\r
9476 char * pc = lpUserGLT;
\r
9478 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9482 id = GLT_ListItemToTag( hDlg, idx );
\r
9486 } while( id != '\0' );
\r
9488 EndDialog( hDlg, 0 );
\r
9491 EndDialog( hDlg, 1 );
\r
9494 case IDC_GLT_Default:
\r
9495 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9496 GLT_TagsToList( hDlg, glt );
\r
9499 case IDC_GLT_Restore:
\r
9500 strcpy( glt, lpUserGLT );
\r
9501 GLT_TagsToList( hDlg, glt );
\r
9505 GLT_MoveSelection( hDlg, -1 );
\r
9508 case IDC_GLT_Down:
\r
9509 GLT_MoveSelection( hDlg, +1 );
\r
9519 int GameListOptions()
\r
9523 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9525 strcpy( glt, appData.gameListTags );
\r
9527 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9529 if( result == 0 ) {
\r
9530 /* [AS] Memory leak here! */
\r
9531 appData.gameListTags = strdup( glt );
\r
9539 DisplayIcsInteractionTitle(char *str)
\r
9541 char consoleTitle[MSG_SIZ];
\r
9543 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9544 SetWindowText(hwndConsole, consoleTitle);
\r
9548 DrawPosition(int fullRedraw, Board board)
\r
9550 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9553 void NotifyFrontendLogin()
\r
9556 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9562 fromX = fromY = -1;
\r
9563 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9564 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9565 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9566 dragInfo.lastpos = dragInfo.pos;
\r
9567 dragInfo.start.x = dragInfo.start.y = -1;
\r
9568 dragInfo.from = dragInfo.start;
\r
9570 DrawPosition(TRUE, NULL);
\r
9576 CommentPopUp(char *title, char *str)
\r
9578 HWND hwnd = GetActiveWindow();
\r
9579 EitherCommentPopUp(0, title, str, FALSE);
\r
9581 SetActiveWindow(hwnd);
\r
9585 CommentPopDown(void)
\r
9587 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9588 if (commentDialog) {
\r
9589 ShowWindow(commentDialog, SW_HIDE);
\r
9591 commentDialogUp = FALSE;
\r
9595 EditCommentPopUp(int index, char *title, char *str)
\r
9597 EitherCommentPopUp(index, title, str, TRUE);
\r
9604 MyPlaySound(&sounds[(int)SoundMove]);
\r
9607 VOID PlayIcsWinSound()
\r
9609 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9612 VOID PlayIcsLossSound()
\r
9614 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9617 VOID PlayIcsDrawSound()
\r
9619 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9622 VOID PlayIcsUnfinishedSound()
\r
9624 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9630 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9638 consoleEcho = TRUE;
\r
9639 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9640 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9641 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9650 consoleEcho = FALSE;
\r
9651 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9652 /* This works OK: set text and background both to the same color */
\r
9654 cf.crTextColor = COLOR_ECHOOFF;
\r
9655 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9656 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9659 /* No Raw()...? */
\r
9661 void Colorize(ColorClass cc, int continuation)
\r
9663 currentColorClass = cc;
\r
9664 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9665 consoleCF.crTextColor = textAttribs[cc].color;
\r
9666 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9667 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9673 static char buf[MSG_SIZ];
\r
9674 DWORD bufsiz = MSG_SIZ;
\r
9676 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9677 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9679 if (!GetUserName(buf, &bufsiz)) {
\r
9680 /*DisplayError("Error getting user name", GetLastError());*/
\r
9681 strcpy(buf, "User");
\r
9689 static char buf[MSG_SIZ];
\r
9690 DWORD bufsiz = MSG_SIZ;
\r
9692 if (!GetComputerName(buf, &bufsiz)) {
\r
9693 /*DisplayError("Error getting host name", GetLastError());*/
\r
9694 strcpy(buf, "Unknown");
\r
9701 ClockTimerRunning()
\r
9703 return clockTimerEvent != 0;
\r
9709 if (clockTimerEvent == 0) return FALSE;
\r
9710 KillTimer(hwndMain, clockTimerEvent);
\r
9711 clockTimerEvent = 0;
\r
9716 StartClockTimer(long millisec)
\r
9718 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9719 (UINT) millisec, NULL);
\r
9723 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9726 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9728 if(appData.noGUI) return;
\r
9729 hdc = GetDC(hwndMain);
\r
9730 if (!IsIconic(hwndMain)) {
\r
9731 DisplayAClock(hdc, timeRemaining, highlight,
\r
9732 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9734 if (highlight && iconCurrent == iconBlack) {
\r
9735 iconCurrent = iconWhite;
\r
9736 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9737 if (IsIconic(hwndMain)) {
\r
9738 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9741 (void) ReleaseDC(hwndMain, hdc);
\r
9743 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9747 DisplayBlackClock(long timeRemaining, int highlight)
\r
9750 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9752 if(appData.noGUI) return;
\r
9753 hdc = GetDC(hwndMain);
\r
9754 if (!IsIconic(hwndMain)) {
\r
9755 DisplayAClock(hdc, timeRemaining, highlight,
\r
9756 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9758 if (highlight && iconCurrent == iconWhite) {
\r
9759 iconCurrent = iconBlack;
\r
9760 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9761 if (IsIconic(hwndMain)) {
\r
9762 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9765 (void) ReleaseDC(hwndMain, hdc);
\r
9767 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9772 LoadGameTimerRunning()
\r
9774 return loadGameTimerEvent != 0;
\r
9778 StopLoadGameTimer()
\r
9780 if (loadGameTimerEvent == 0) return FALSE;
\r
9781 KillTimer(hwndMain, loadGameTimerEvent);
\r
9782 loadGameTimerEvent = 0;
\r
9787 StartLoadGameTimer(long millisec)
\r
9789 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9790 (UINT) millisec, NULL);
\r
9798 char fileTitle[MSG_SIZ];
\r
9800 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9801 f = OpenFileDialog(hwndMain, "a", defName,
\r
9802 appData.oldSaveStyle ? "gam" : "pgn",
\r
9804 "Save Game to File", NULL, fileTitle, NULL);
\r
9806 SaveGame(f, 0, "");
\r
9813 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9815 if (delayedTimerEvent != 0) {
\r
9816 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9817 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9819 KillTimer(hwndMain, delayedTimerEvent);
\r
9820 delayedTimerEvent = 0;
\r
9821 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9822 delayedTimerCallback();
\r
9824 delayedTimerCallback = cb;
\r
9825 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9826 (UINT) millisec, NULL);
\r
9829 DelayedEventCallback
\r
9832 if (delayedTimerEvent) {
\r
9833 return delayedTimerCallback;
\r
9840 CancelDelayedEvent()
\r
9842 if (delayedTimerEvent) {
\r
9843 KillTimer(hwndMain, delayedTimerEvent);
\r
9844 delayedTimerEvent = 0;
\r
9848 DWORD GetWin32Priority(int nice)
\r
9849 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9851 REALTIME_PRIORITY_CLASS 0x00000100
\r
9852 HIGH_PRIORITY_CLASS 0x00000080
\r
9853 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9854 NORMAL_PRIORITY_CLASS 0x00000020
\r
9855 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9856 IDLE_PRIORITY_CLASS 0x00000040
\r
9858 if (nice < -15) return 0x00000080;
\r
9859 if (nice < 0) return 0x00008000;
\r
9860 if (nice == 0) return 0x00000020;
\r
9861 if (nice < 15) return 0x00004000;
\r
9862 return 0x00000040;
\r
9865 /* Start a child process running the given program.
\r
9866 The process's standard output can be read from "from", and its
\r
9867 standard input can be written to "to".
\r
9868 Exit with fatal error if anything goes wrong.
\r
9869 Returns an opaque pointer that can be used to destroy the process
\r
9873 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9875 #define BUFSIZE 4096
\r
9877 HANDLE hChildStdinRd, hChildStdinWr,
\r
9878 hChildStdoutRd, hChildStdoutWr;
\r
9879 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9880 SECURITY_ATTRIBUTES saAttr;
\r
9882 PROCESS_INFORMATION piProcInfo;
\r
9883 STARTUPINFO siStartInfo;
\r
9885 char buf[MSG_SIZ];
\r
9888 if (appData.debugMode) {
\r
9889 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9894 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9895 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9896 saAttr.bInheritHandle = TRUE;
\r
9897 saAttr.lpSecurityDescriptor = NULL;
\r
9900 * The steps for redirecting child's STDOUT:
\r
9901 * 1. Create anonymous pipe to be STDOUT for child.
\r
9902 * 2. Create a noninheritable duplicate of read handle,
\r
9903 * and close the inheritable read handle.
\r
9906 /* Create a pipe for the child's STDOUT. */
\r
9907 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9908 return GetLastError();
\r
9911 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9912 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9913 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9914 FALSE, /* not inherited */
\r
9915 DUPLICATE_SAME_ACCESS);
\r
9917 return GetLastError();
\r
9919 CloseHandle(hChildStdoutRd);
\r
9922 * The steps for redirecting child's STDIN:
\r
9923 * 1. Create anonymous pipe to be STDIN for child.
\r
9924 * 2. Create a noninheritable duplicate of write handle,
\r
9925 * and close the inheritable write handle.
\r
9928 /* Create a pipe for the child's STDIN. */
\r
9929 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9930 return GetLastError();
\r
9933 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9934 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9935 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9936 FALSE, /* not inherited */
\r
9937 DUPLICATE_SAME_ACCESS);
\r
9939 return GetLastError();
\r
9941 CloseHandle(hChildStdinWr);
\r
9943 /* Arrange to (1) look in dir for the child .exe file, and
\r
9944 * (2) have dir be the child's working directory. Interpret
\r
9945 * dir relative to the directory WinBoard loaded from. */
\r
9946 GetCurrentDirectory(MSG_SIZ, buf);
\r
9947 SetCurrentDirectory(installDir);
\r
9948 SetCurrentDirectory(dir);
\r
9950 /* Now create the child process. */
\r
9952 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9953 siStartInfo.lpReserved = NULL;
\r
9954 siStartInfo.lpDesktop = NULL;
\r
9955 siStartInfo.lpTitle = NULL;
\r
9956 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9957 siStartInfo.cbReserved2 = 0;
\r
9958 siStartInfo.lpReserved2 = NULL;
\r
9959 siStartInfo.hStdInput = hChildStdinRd;
\r
9960 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9961 siStartInfo.hStdError = hChildStdoutWr;
\r
9963 fSuccess = CreateProcess(NULL,
\r
9964 cmdLine, /* command line */
\r
9965 NULL, /* process security attributes */
\r
9966 NULL, /* primary thread security attrs */
\r
9967 TRUE, /* handles are inherited */
\r
9968 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9969 NULL, /* use parent's environment */
\r
9971 &siStartInfo, /* STARTUPINFO pointer */
\r
9972 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9974 err = GetLastError();
\r
9975 SetCurrentDirectory(buf); /* return to prev directory */
\r
9980 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9981 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9982 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9985 /* Close the handles we don't need in the parent */
\r
9986 CloseHandle(piProcInfo.hThread);
\r
9987 CloseHandle(hChildStdinRd);
\r
9988 CloseHandle(hChildStdoutWr);
\r
9990 /* Prepare return value */
\r
9991 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9992 cp->kind = CPReal;
\r
9993 cp->hProcess = piProcInfo.hProcess;
\r
9994 cp->pid = piProcInfo.dwProcessId;
\r
9995 cp->hFrom = hChildStdoutRdDup;
\r
9996 cp->hTo = hChildStdinWrDup;
\r
9998 *pr = (void *) cp;
\r
10000 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10001 2000 where engines sometimes don't see the initial command(s)
\r
10002 from WinBoard and hang. I don't understand how that can happen,
\r
10003 but the Sleep is harmless, so I've put it in. Others have also
\r
10004 reported what may be the same problem, so hopefully this will fix
\r
10005 it for them too. */
\r
10013 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10015 ChildProc *cp; int result;
\r
10017 cp = (ChildProc *) pr;
\r
10018 if (cp == NULL) return;
\r
10020 switch (cp->kind) {
\r
10022 /* TerminateProcess is considered harmful, so... */
\r
10023 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10024 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10025 /* The following doesn't work because the chess program
\r
10026 doesn't "have the same console" as WinBoard. Maybe
\r
10027 we could arrange for this even though neither WinBoard
\r
10028 nor the chess program uses a console for stdio? */
\r
10029 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10031 /* [AS] Special termination modes for misbehaving programs... */
\r
10032 if( signal == 9 ) {
\r
10033 result = TerminateProcess( cp->hProcess, 0 );
\r
10035 if ( appData.debugMode) {
\r
10036 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10039 else if( signal == 10 ) {
\r
10040 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10042 if( dw != WAIT_OBJECT_0 ) {
\r
10043 result = TerminateProcess( cp->hProcess, 0 );
\r
10045 if ( appData.debugMode) {
\r
10046 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10052 CloseHandle(cp->hProcess);
\r
10056 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10060 closesocket(cp->sock);
\r
10065 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10066 closesocket(cp->sock);
\r
10067 closesocket(cp->sock2);
\r
10075 InterruptChildProcess(ProcRef pr)
\r
10079 cp = (ChildProc *) pr;
\r
10080 if (cp == NULL) return;
\r
10081 switch (cp->kind) {
\r
10083 /* The following doesn't work because the chess program
\r
10084 doesn't "have the same console" as WinBoard. Maybe
\r
10085 we could arrange for this even though neither WinBoard
\r
10086 nor the chess program uses a console for stdio */
\r
10087 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10092 /* Can't interrupt */
\r
10096 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10103 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10105 char cmdLine[MSG_SIZ];
\r
10107 if (port[0] == NULLCHAR) {
\r
10108 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10110 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10112 return StartChildProcess(cmdLine, "", pr);
\r
10116 /* Code to open TCP sockets */
\r
10119 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10124 struct sockaddr_in sa, mysa;
\r
10125 struct hostent FAR *hp;
\r
10126 unsigned short uport;
\r
10127 WORD wVersionRequested;
\r
10130 /* Initialize socket DLL */
\r
10131 wVersionRequested = MAKEWORD(1, 1);
\r
10132 err = WSAStartup(wVersionRequested, &wsaData);
\r
10133 if (err != 0) return err;
\r
10135 /* Make socket */
\r
10136 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10137 err = WSAGetLastError();
\r
10142 /* Bind local address using (mostly) don't-care values.
\r
10144 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10145 mysa.sin_family = AF_INET;
\r
10146 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10147 uport = (unsigned short) 0;
\r
10148 mysa.sin_port = htons(uport);
\r
10149 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10150 == SOCKET_ERROR) {
\r
10151 err = WSAGetLastError();
\r
10156 /* Resolve remote host name */
\r
10157 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10158 if (!(hp = gethostbyname(host))) {
\r
10159 unsigned int b0, b1, b2, b3;
\r
10161 err = WSAGetLastError();
\r
10163 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10164 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10165 hp->h_addrtype = AF_INET;
\r
10166 hp->h_length = 4;
\r
10167 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10168 hp->h_addr_list[0] = (char *) malloc(4);
\r
10169 hp->h_addr_list[0][0] = (char) b0;
\r
10170 hp->h_addr_list[0][1] = (char) b1;
\r
10171 hp->h_addr_list[0][2] = (char) b2;
\r
10172 hp->h_addr_list[0][3] = (char) b3;
\r
10178 sa.sin_family = hp->h_addrtype;
\r
10179 uport = (unsigned short) atoi(port);
\r
10180 sa.sin_port = htons(uport);
\r
10181 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10183 /* Make connection */
\r
10184 if (connect(s, (struct sockaddr *) &sa,
\r
10185 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10186 err = WSAGetLastError();
\r
10191 /* Prepare return value */
\r
10192 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10193 cp->kind = CPSock;
\r
10195 *pr = (ProcRef *) cp;
\r
10201 OpenCommPort(char *name, ProcRef *pr)
\r
10206 char fullname[MSG_SIZ];
\r
10208 if (*name != '\\')
\r
10209 sprintf(fullname, "\\\\.\\%s", name);
\r
10211 strcpy(fullname, name);
\r
10213 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10214 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10215 if (h == (HANDLE) -1) {
\r
10216 return GetLastError();
\r
10220 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10222 /* Accumulate characters until a 100ms pause, then parse */
\r
10223 ct.ReadIntervalTimeout = 100;
\r
10224 ct.ReadTotalTimeoutMultiplier = 0;
\r
10225 ct.ReadTotalTimeoutConstant = 0;
\r
10226 ct.WriteTotalTimeoutMultiplier = 0;
\r
10227 ct.WriteTotalTimeoutConstant = 0;
\r
10228 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10230 /* Prepare return value */
\r
10231 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10232 cp->kind = CPComm;
\r
10235 *pr = (ProcRef *) cp;
\r
10241 OpenLoopback(ProcRef *pr)
\r
10243 DisplayFatalError("Not implemented", 0, 1);
\r
10249 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10253 SOCKET s, s2, s3;
\r
10254 struct sockaddr_in sa, mysa;
\r
10255 struct hostent FAR *hp;
\r
10256 unsigned short uport;
\r
10257 WORD wVersionRequested;
\r
10260 char stderrPortStr[MSG_SIZ];
\r
10262 /* Initialize socket DLL */
\r
10263 wVersionRequested = MAKEWORD(1, 1);
\r
10264 err = WSAStartup(wVersionRequested, &wsaData);
\r
10265 if (err != 0) return err;
\r
10267 /* Resolve remote host name */
\r
10268 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10269 if (!(hp = gethostbyname(host))) {
\r
10270 unsigned int b0, b1, b2, b3;
\r
10272 err = WSAGetLastError();
\r
10274 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10275 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10276 hp->h_addrtype = AF_INET;
\r
10277 hp->h_length = 4;
\r
10278 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10279 hp->h_addr_list[0] = (char *) malloc(4);
\r
10280 hp->h_addr_list[0][0] = (char) b0;
\r
10281 hp->h_addr_list[0][1] = (char) b1;
\r
10282 hp->h_addr_list[0][2] = (char) b2;
\r
10283 hp->h_addr_list[0][3] = (char) b3;
\r
10289 sa.sin_family = hp->h_addrtype;
\r
10290 uport = (unsigned short) 514;
\r
10291 sa.sin_port = htons(uport);
\r
10292 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10294 /* Bind local socket to unused "privileged" port address
\r
10296 s = INVALID_SOCKET;
\r
10297 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10298 mysa.sin_family = AF_INET;
\r
10299 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10300 for (fromPort = 1023;; fromPort--) {
\r
10301 if (fromPort < 0) {
\r
10303 return WSAEADDRINUSE;
\r
10305 if (s == INVALID_SOCKET) {
\r
10306 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10307 err = WSAGetLastError();
\r
10312 uport = (unsigned short) fromPort;
\r
10313 mysa.sin_port = htons(uport);
\r
10314 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10315 == SOCKET_ERROR) {
\r
10316 err = WSAGetLastError();
\r
10317 if (err == WSAEADDRINUSE) continue;
\r
10321 if (connect(s, (struct sockaddr *) &sa,
\r
10322 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10323 err = WSAGetLastError();
\r
10324 if (err == WSAEADDRINUSE) {
\r
10335 /* Bind stderr local socket to unused "privileged" port address
\r
10337 s2 = INVALID_SOCKET;
\r
10338 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10339 mysa.sin_family = AF_INET;
\r
10340 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10341 for (fromPort = 1023;; fromPort--) {
\r
10342 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10343 if (fromPort < 0) {
\r
10344 (void) closesocket(s);
\r
10346 return WSAEADDRINUSE;
\r
10348 if (s2 == INVALID_SOCKET) {
\r
10349 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10350 err = WSAGetLastError();
\r
10356 uport = (unsigned short) fromPort;
\r
10357 mysa.sin_port = htons(uport);
\r
10358 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10359 == SOCKET_ERROR) {
\r
10360 err = WSAGetLastError();
\r
10361 if (err == WSAEADDRINUSE) continue;
\r
10362 (void) closesocket(s);
\r
10366 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10367 err = WSAGetLastError();
\r
10368 if (err == WSAEADDRINUSE) {
\r
10370 s2 = INVALID_SOCKET;
\r
10373 (void) closesocket(s);
\r
10374 (void) closesocket(s2);
\r
10380 prevStderrPort = fromPort; // remember port used
\r
10381 sprintf(stderrPortStr, "%d", fromPort);
\r
10383 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10384 err = WSAGetLastError();
\r
10385 (void) closesocket(s);
\r
10386 (void) closesocket(s2);
\r
10391 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10392 err = WSAGetLastError();
\r
10393 (void) closesocket(s);
\r
10394 (void) closesocket(s2);
\r
10398 if (*user == NULLCHAR) user = UserName();
\r
10399 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10400 err = WSAGetLastError();
\r
10401 (void) closesocket(s);
\r
10402 (void) closesocket(s2);
\r
10406 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10407 err = WSAGetLastError();
\r
10408 (void) closesocket(s);
\r
10409 (void) closesocket(s2);
\r
10414 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10415 err = WSAGetLastError();
\r
10416 (void) closesocket(s);
\r
10417 (void) closesocket(s2);
\r
10421 (void) closesocket(s2); /* Stop listening */
\r
10423 /* Prepare return value */
\r
10424 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10425 cp->kind = CPRcmd;
\r
10428 *pr = (ProcRef *) cp;
\r
10435 AddInputSource(ProcRef pr, int lineByLine,
\r
10436 InputCallback func, VOIDSTAR closure)
\r
10438 InputSource *is, *is2 = NULL;
\r
10439 ChildProc *cp = (ChildProc *) pr;
\r
10441 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10442 is->lineByLine = lineByLine;
\r
10444 is->closure = closure;
\r
10445 is->second = NULL;
\r
10446 is->next = is->buf;
\r
10447 if (pr == NoProc) {
\r
10448 is->kind = CPReal;
\r
10449 consoleInputSource = is;
\r
10451 is->kind = cp->kind;
\r
10453 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10454 we create all threads suspended so that the is->hThread variable can be
\r
10455 safely assigned, then let the threads start with ResumeThread.
\r
10457 switch (cp->kind) {
\r
10459 is->hFile = cp->hFrom;
\r
10460 cp->hFrom = NULL; /* now owned by InputThread */
\r
10462 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10463 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10467 is->hFile = cp->hFrom;
\r
10468 cp->hFrom = NULL; /* now owned by InputThread */
\r
10470 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10471 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10475 is->sock = cp->sock;
\r
10477 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10478 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10482 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10484 is->sock = cp->sock;
\r
10485 is->second = is2;
\r
10486 is2->sock = cp->sock2;
\r
10487 is2->second = is2;
\r
10489 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10490 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10492 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10493 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10497 if( is->hThread != NULL ) {
\r
10498 ResumeThread( is->hThread );
\r
10501 if( is2 != NULL && is2->hThread != NULL ) {
\r
10502 ResumeThread( is2->hThread );
\r
10506 return (InputSourceRef) is;
\r
10510 RemoveInputSource(InputSourceRef isr)
\r
10514 is = (InputSource *) isr;
\r
10515 is->hThread = NULL; /* tell thread to stop */
\r
10516 CloseHandle(is->hThread);
\r
10517 if (is->second != NULL) {
\r
10518 is->second->hThread = NULL;
\r
10519 CloseHandle(is->second->hThread);
\r
10525 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10528 int outCount = SOCKET_ERROR;
\r
10529 ChildProc *cp = (ChildProc *) pr;
\r
10530 static OVERLAPPED ovl;
\r
10532 if (pr == NoProc) {
\r
10533 ConsoleOutput(message, count, FALSE);
\r
10537 if (ovl.hEvent == NULL) {
\r
10538 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10540 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10542 switch (cp->kind) {
\r
10545 outCount = send(cp->sock, message, count, 0);
\r
10546 if (outCount == SOCKET_ERROR) {
\r
10547 *outError = WSAGetLastError();
\r
10549 *outError = NO_ERROR;
\r
10554 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10555 &dOutCount, NULL)) {
\r
10556 *outError = NO_ERROR;
\r
10557 outCount = (int) dOutCount;
\r
10559 *outError = GetLastError();
\r
10564 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10565 &dOutCount, &ovl);
\r
10566 if (*outError == NO_ERROR) {
\r
10567 outCount = (int) dOutCount;
\r
10575 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10578 /* Ignore delay, not implemented for WinBoard */
\r
10579 return OutputToProcess(pr, message, count, outError);
\r
10584 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10585 char *buf, int count, int error)
\r
10587 DisplayFatalError("Not implemented", 0, 1);
\r
10590 /* see wgamelist.c for Game List functions */
\r
10591 /* see wedittags.c for Edit Tags functions */
\r
10598 char buf[MSG_SIZ];
\r
10601 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10602 f = fopen(buf, "r");
\r
10604 ProcessICSInitScript(f);
\r
10612 StartAnalysisClock()
\r
10614 if (analysisTimerEvent) return;
\r
10615 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10616 (UINT) 2000, NULL);
\r
10620 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10622 static HANDLE hwndText;
\r
10624 static int sizeX, sizeY;
\r
10625 int newSizeX, newSizeY, flags;
\r
10628 switch (message) {
\r
10629 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10630 /* Initialize the dialog items */
\r
10631 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10632 SetWindowText(hDlg, analysisTitle);
\r
10633 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10634 /* Size and position the dialog */
\r
10635 if (!analysisDialog) {
\r
10636 analysisDialog = hDlg;
\r
10637 flags = SWP_NOZORDER;
\r
10638 GetClientRect(hDlg, &rect);
\r
10639 sizeX = rect.right;
\r
10640 sizeY = rect.bottom;
\r
10641 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10642 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10643 WINDOWPLACEMENT wp;
\r
10644 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10645 wp.length = sizeof(WINDOWPLACEMENT);
\r
10647 wp.showCmd = SW_SHOW;
\r
10648 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10649 wp.rcNormalPosition.left = analysisX;
\r
10650 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10651 wp.rcNormalPosition.top = analysisY;
\r
10652 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10653 SetWindowPlacement(hDlg, &wp);
\r
10655 GetClientRect(hDlg, &rect);
\r
10656 newSizeX = rect.right;
\r
10657 newSizeY = rect.bottom;
\r
10658 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10659 newSizeX, newSizeY);
\r
10660 sizeX = newSizeX;
\r
10661 sizeY = newSizeY;
\r
10666 case WM_COMMAND: /* message: received a command */
\r
10667 switch (LOWORD(wParam)) {
\r
10669 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10670 ExitAnalyzeMode();
\r
10682 newSizeX = LOWORD(lParam);
\r
10683 newSizeY = HIWORD(lParam);
\r
10684 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10685 sizeX = newSizeX;
\r
10686 sizeY = newSizeY;
\r
10689 case WM_GETMINMAXINFO:
\r
10690 /* Prevent resizing window too small */
\r
10691 mmi = (MINMAXINFO *) lParam;
\r
10692 mmi->ptMinTrackSize.x = 100;
\r
10693 mmi->ptMinTrackSize.y = 100;
\r
10700 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10702 highlightInfo.sq[0].x = fromX;
\r
10703 highlightInfo.sq[0].y = fromY;
\r
10704 highlightInfo.sq[1].x = toX;
\r
10705 highlightInfo.sq[1].y = toY;
\r
10709 ClearHighlights()
\r
10711 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10712 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10716 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10718 premoveHighlightInfo.sq[0].x = fromX;
\r
10719 premoveHighlightInfo.sq[0].y = fromY;
\r
10720 premoveHighlightInfo.sq[1].x = toX;
\r
10721 premoveHighlightInfo.sq[1].y = toY;
\r
10725 ClearPremoveHighlights()
\r
10727 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10728 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10732 ShutDownFrontEnd()
\r
10734 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10735 DeleteClipboardTempFiles();
\r
10741 if (IsIconic(hwndMain))
\r
10742 ShowWindow(hwndMain, SW_RESTORE);
\r
10744 SetActiveWindow(hwndMain);
\r
10748 * Prototypes for animation support routines
\r
10750 static void ScreenSquare(int column, int row, POINT * pt);
\r
10751 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10752 POINT frames[], int * nFrames);
\r
10756 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10757 { // [HGM] atomic: animate blast wave
\r
10759 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10760 explodeInfo.fromX = fromX;
\r
10761 explodeInfo.fromY = fromY;
\r
10762 explodeInfo.toX = toX;
\r
10763 explodeInfo.toY = toY;
\r
10764 for(i=1; i<nFrames; i++) {
\r
10765 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10766 DrawPosition(FALSE, NULL);
\r
10767 Sleep(appData.animSpeed);
\r
10769 explodeInfo.radius = 0;
\r
10770 DrawPosition(TRUE, NULL);
\r
10773 #define kFactor 4
\r
10776 AnimateMove(board, fromX, fromY, toX, toY)
\r
10783 ChessSquare piece;
\r
10784 POINT start, finish, mid;
\r
10785 POINT frames[kFactor * 2 + 1];
\r
10788 if (!appData.animate) return;
\r
10789 if (doingSizing) return;
\r
10790 if (fromY < 0 || fromX < 0) return;
\r
10791 piece = board[fromY][fromX];
\r
10792 if (piece >= EmptySquare) return;
\r
10794 ScreenSquare(fromX, fromY, &start);
\r
10795 ScreenSquare(toX, toY, &finish);
\r
10797 /* All pieces except knights move in straight line */
\r
10798 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10799 mid.x = start.x + (finish.x - start.x) / 2;
\r
10800 mid.y = start.y + (finish.y - start.y) / 2;
\r
10802 /* Knight: make diagonal movement then straight */
\r
10803 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10804 mid.x = start.x + (finish.x - start.x) / 2;
\r
10805 mid.y = finish.y;
\r
10807 mid.x = finish.x;
\r
10808 mid.y = start.y + (finish.y - start.y) / 2;
\r
10812 /* Don't use as many frames for very short moves */
\r
10813 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10814 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10816 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10818 animInfo.from.x = fromX;
\r
10819 animInfo.from.y = fromY;
\r
10820 animInfo.to.x = toX;
\r
10821 animInfo.to.y = toY;
\r
10822 animInfo.lastpos = start;
\r
10823 animInfo.piece = piece;
\r
10824 for (n = 0; n < nFrames; n++) {
\r
10825 animInfo.pos = frames[n];
\r
10826 DrawPosition(FALSE, NULL);
\r
10827 animInfo.lastpos = animInfo.pos;
\r
10828 Sleep(appData.animSpeed);
\r
10830 animInfo.pos = finish;
\r
10831 DrawPosition(FALSE, NULL);
\r
10832 animInfo.piece = EmptySquare;
\r
10833 if(gameInfo.variant == VariantAtomic &&
\r
10834 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10835 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10838 /* Convert board position to corner of screen rect and color */
\r
10841 ScreenSquare(column, row, pt)
\r
10842 int column; int row; POINT * pt;
\r
10845 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10846 pt->y = lineGap + row * (squareSize + lineGap);
\r
10848 pt->x = lineGap + column * (squareSize + lineGap);
\r
10849 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10853 /* Generate a series of frame coords from start->mid->finish.
\r
10854 The movement rate doubles until the half way point is
\r
10855 reached, then halves back down to the final destination,
\r
10856 which gives a nice slow in/out effect. The algorithmn
\r
10857 may seem to generate too many intermediates for short
\r
10858 moves, but remember that the purpose is to attract the
\r
10859 viewers attention to the piece about to be moved and
\r
10860 then to where it ends up. Too few frames would be less
\r
10864 Tween(start, mid, finish, factor, frames, nFrames)
\r
10865 POINT * start; POINT * mid;
\r
10866 POINT * finish; int factor;
\r
10867 POINT frames[]; int * nFrames;
\r
10869 int n, fraction = 1, count = 0;
\r
10871 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10872 for (n = 0; n < factor; n++)
\r
10874 for (n = 0; n < factor; n++) {
\r
10875 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10876 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10878 fraction = fraction / 2;
\r
10882 frames[count] = *mid;
\r
10885 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10887 for (n = 0; n < factor; n++) {
\r
10888 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10889 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10891 fraction = fraction * 2;
\r
10893 *nFrames = count;
\r
10897 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10899 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10901 EvalGraphSet( first, last, current, pvInfoList );
\r
10904 void SetProgramStats( FrontEndProgramStats * stats )
\r
10906 EngineOutputUpdate( stats );
\r