2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
291 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
292 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
293 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
294 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 BOOLEAN commentDialogUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 BOOLEAN engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1396 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1397 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1398 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1399 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1400 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1401 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1402 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1403 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1404 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1405 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1406 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1407 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1408 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1409 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1410 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1411 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1412 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1413 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1414 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1415 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1416 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1417 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1418 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1419 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1420 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1421 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1422 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1423 /* [AS] Layout stuff */
\r
1424 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1425 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1426 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1427 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1428 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1430 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1431 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1432 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1433 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1434 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1436 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1437 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1438 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1439 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1440 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1442 { NULL, ArgNone, NULL, FALSE }
\r
1446 /* Kludge for indirection files on command line */
\r
1447 char* lastIndirectionFilename;
\r
1448 ArgDescriptor argDescriptorIndirection =
\r
1449 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1453 ExitArgError(char *msg, char *badArg)
\r
1455 char buf[MSG_SIZ];
\r
1457 sprintf(buf, "%s %s", msg, badArg);
\r
1458 DisplayFatalError(buf, 0, 2);
\r
1462 /* Command line font name parser. NULL name means do nothing.
\r
1463 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1464 For backward compatibility, syntax without the colon is also
\r
1465 accepted, but font names with digits in them won't work in that case.
\r
1468 ParseFontName(char *name, MyFontParams *mfp)
\r
1471 if (name == NULL) return;
\r
1473 q = strchr(p, ':');
\r
1475 if (q - p >= sizeof(mfp->faceName))
\r
1476 ExitArgError("Font name too long:", name);
\r
1477 memcpy(mfp->faceName, p, q - p);
\r
1478 mfp->faceName[q - p] = NULLCHAR;
\r
1481 q = mfp->faceName;
\r
1482 while (*p && !isdigit(*p)) {
\r
1484 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1485 ExitArgError("Font name too long:", name);
\r
1487 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1490 if (!*p) ExitArgError("Font point size missing:", name);
\r
1491 mfp->pointSize = (float) atof(p);
\r
1492 mfp->bold = (strchr(p, 'b') != NULL);
\r
1493 mfp->italic = (strchr(p, 'i') != NULL);
\r
1494 mfp->underline = (strchr(p, 'u') != NULL);
\r
1495 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1498 /* Color name parser.
\r
1499 X version accepts X color names, but this one
\r
1500 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1502 ParseColorName(char *name)
\r
1504 int red, green, blue, count;
\r
1505 char buf[MSG_SIZ];
\r
1507 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1509 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1510 &red, &green, &blue);
\r
1513 sprintf(buf, "Can't parse color name %s", name);
\r
1514 DisplayError(buf, 0);
\r
1515 return RGB(0, 0, 0);
\r
1517 return PALETTERGB(red, green, blue);
\r
1521 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1523 char *e = argValue;
\r
1527 if (*e == 'b') eff |= CFE_BOLD;
\r
1528 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1529 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1530 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1531 else if (*e == '#' || isdigit(*e)) break;
\r
1535 *color = ParseColorName(e);
\r
1540 ParseBoardSize(char *name)
\r
1542 BoardSize bs = SizeTiny;
\r
1543 while (sizeInfo[bs].name != NULL) {
\r
1544 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1547 ExitArgError("Unrecognized board size value", name);
\r
1548 return bs; /* not reached */
\r
1553 StringGet(void *getClosure)
\r
1555 char **p = (char **) getClosure;
\r
1560 FileGet(void *getClosure)
\r
1563 FILE* f = (FILE*) getClosure;
\r
1566 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1573 /* Parse settings file named "name". If file found, return the
\r
1574 full name in fullname and return TRUE; else return FALSE */
\r
1576 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1580 int ok; char buf[MSG_SIZ];
\r
1582 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1583 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1584 sprintf(buf, "%s.ini", name);
\r
1585 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1588 f = fopen(fullname, "r");
\r
1590 ParseArgs(FileGet, f);
\r
1599 ParseArgs(GetFunc get, void *cl)
\r
1601 char argName[ARG_MAX];
\r
1602 char argValue[ARG_MAX];
\r
1603 ArgDescriptor *ad;
\r
1612 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1613 if (ch == NULLCHAR) break;
\r
1615 /* Comment to end of line */
\r
1617 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1619 } else if (ch == '/' || ch == '-') {
\r
1622 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1623 ch != '\n' && ch != '\t') {
\r
1629 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1630 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1632 if (ad->argName == NULL)
\r
1633 ExitArgError("Unrecognized argument", argName);
\r
1635 } else if (ch == '@') {
\r
1636 /* Indirection file */
\r
1637 ad = &argDescriptorIndirection;
\r
1640 /* Positional argument */
\r
1641 ad = &argDescriptors[posarg++];
\r
1642 strcpy(argName, ad->argName);
\r
1645 if (ad->argType == ArgTrue) {
\r
1646 *(Boolean *) ad->argLoc = TRUE;
\r
1649 if (ad->argType == ArgFalse) {
\r
1650 *(Boolean *) ad->argLoc = FALSE;
\r
1654 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1655 if (ch == NULLCHAR || ch == '\n') {
\r
1656 ExitArgError("No value provided for argument", argName);
\r
1660 // Quoting with { }. No characters have to (or can) be escaped.
\r
1661 // Thus the string cannot contain a '}' character.
\r
1681 } else if (ch == '\'' || ch == '"') {
\r
1682 // Quoting with ' ' or " ", with \ as escape character.
\r
1683 // Inconvenient for long strings that may contain Windows filenames.
\r
1700 if (ch == start) {
\r
1709 if (ad->argType == ArgFilename
\r
1710 || ad->argType == ArgSettingsFilename) {
\r
1716 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1740 for (i = 0; i < 3; i++) {
\r
1741 if (ch >= '0' && ch <= '7') {
\r
1742 octval = octval*8 + (ch - '0');
\r
1749 *q++ = (char) octval;
\r
1760 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1767 switch (ad->argType) {
\r
1769 *(int *) ad->argLoc = atoi(argValue);
\r
1773 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1781 *(int *) ad->argLoc = atoi(argValue);
\r
1782 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1786 *(float *) ad->argLoc = (float) atof(argValue);
\r
1791 *(char **) ad->argLoc = strdup(argValue);
\r
1794 case ArgSettingsFilename:
\r
1796 char fullname[MSG_SIZ];
\r
1797 if (ParseSettingsFile(argValue, fullname)) {
\r
1798 if (ad->argLoc != NULL) {
\r
1799 *(char **) ad->argLoc = strdup(fullname);
\r
1802 if (ad->argLoc != NULL) {
\r
1804 ExitArgError("Failed to open indirection file", argValue);
\r
1811 switch (argValue[0]) {
\r
1814 *(Boolean *) ad->argLoc = TRUE;
\r
1818 *(Boolean *) ad->argLoc = FALSE;
\r
1821 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1827 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1830 case ArgAttribs: {
\r
1831 ColorClass cc = (ColorClass)ad->argLoc;
\r
1832 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1836 case ArgBoardSize:
\r
1837 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1841 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1844 case ArgCommSettings:
\r
1845 ParseCommSettings(argValue, &dcb);
\r
1849 ExitArgError("Unrecognized argument", argValue);
\r
1858 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1860 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1861 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1864 lf->lfEscapement = 0;
\r
1865 lf->lfOrientation = 0;
\r
1866 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1867 lf->lfItalic = mfp->italic;
\r
1868 lf->lfUnderline = mfp->underline;
\r
1869 lf->lfStrikeOut = mfp->strikeout;
\r
1870 lf->lfCharSet = DEFAULT_CHARSET;
\r
1871 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1872 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1873 lf->lfQuality = DEFAULT_QUALITY;
\r
1874 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1875 strcpy(lf->lfFaceName, mfp->faceName);
\r
1879 CreateFontInMF(MyFont *mf)
\r
1881 LFfromMFP(&mf->lf, &mf->mfp);
\r
1882 if (mf->hf) DeleteObject(mf->hf);
\r
1883 mf->hf = CreateFontIndirect(&mf->lf);
\r
1887 SetDefaultTextAttribs()
\r
1890 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1891 ParseAttribs(&textAttribs[cc].color,
\r
1892 &textAttribs[cc].effects,
\r
1893 defaultTextAttribs[cc]);
\r
1898 SetDefaultSounds()
\r
1902 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1903 textAttribs[cc].sound.name = strdup("");
\r
1904 textAttribs[cc].sound.data = NULL;
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 sounds[sc].name = strdup("");
\r
1908 sounds[sc].data = NULL;
\r
1910 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 MyLoadSound(&textAttribs[cc].sound);
\r
1921 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1922 MyLoadSound(&sounds[sc]);
\r
1927 InitAppData(LPSTR lpCmdLine)
\r
1930 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1933 programName = szAppName;
\r
1935 /* Initialize to defaults */
\r
1936 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1937 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1938 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1939 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1940 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1941 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1942 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1943 SetDefaultTextAttribs();
\r
1944 SetDefaultSounds();
\r
1945 appData.movesPerSession = MOVES_PER_SESSION;
\r
1946 appData.initString = INIT_STRING;
\r
1947 appData.secondInitString = INIT_STRING;
\r
1948 appData.firstComputerString = COMPUTER_STRING;
\r
1949 appData.secondComputerString = COMPUTER_STRING;
\r
1950 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1951 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1952 appData.firstPlaysBlack = FALSE;
\r
1953 appData.noChessProgram = FALSE;
\r
1954 chessProgram = FALSE;
\r
1955 appData.firstHost = FIRST_HOST;
\r
1956 appData.secondHost = SECOND_HOST;
\r
1957 appData.firstDirectory = FIRST_DIRECTORY;
\r
1958 appData.secondDirectory = SECOND_DIRECTORY;
\r
1959 appData.bitmapDirectory = "";
\r
1960 appData.remoteShell = REMOTE_SHELL;
\r
1961 appData.remoteUser = "";
\r
1962 appData.timeDelay = TIME_DELAY;
\r
1963 appData.timeControl = TIME_CONTROL;
\r
1964 appData.timeIncrement = TIME_INCREMENT;
\r
1965 appData.icsActive = FALSE;
\r
1966 appData.icsHost = "";
\r
1967 appData.icsPort = ICS_PORT;
\r
1968 appData.icsCommPort = ICS_COMM_PORT;
\r
1969 appData.icsLogon = ICS_LOGON;
\r
1970 appData.icsHelper = "";
\r
1971 appData.useTelnet = FALSE;
\r
1972 appData.telnetProgram = TELNET_PROGRAM;
\r
1973 appData.gateway = "";
\r
1974 appData.loadGameFile = "";
\r
1975 appData.loadGameIndex = 0;
\r
1976 appData.saveGameFile = "";
\r
1977 appData.autoSaveGames = FALSE;
\r
1978 appData.loadPositionFile = "";
\r
1979 appData.loadPositionIndex = 1;
\r
1980 appData.savePositionFile = "";
\r
1981 appData.matchMode = FALSE;
\r
1982 appData.matchGames = 0;
\r
1983 appData.monoMode = FALSE;
\r
1984 appData.debugMode = FALSE;
\r
1985 appData.clockMode = TRUE;
\r
1986 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1987 appData.Iconic = FALSE; /*unused*/
\r
1988 appData.searchTime = "";
\r
1989 appData.searchDepth = 0;
\r
1990 appData.showCoords = FALSE;
\r
1991 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1992 appData.autoCallFlag = FALSE;
\r
1993 appData.flipView = FALSE;
\r
1994 appData.autoFlipView = TRUE;
\r
1995 appData.cmailGameName = "";
\r
1996 appData.alwaysPromoteToQueen = FALSE;
\r
1997 appData.oldSaveStyle = FALSE;
\r
1998 appData.quietPlay = FALSE;
\r
1999 appData.showThinking = FALSE;
\r
2000 appData.ponderNextMove = TRUE;
\r
2001 appData.periodicUpdates = TRUE;
\r
2002 appData.popupExitMessage = TRUE;
\r
2003 appData.popupMoveErrors = FALSE;
\r
2004 appData.autoObserve = FALSE;
\r
2005 appData.autoComment = FALSE;
\r
2006 appData.animate = TRUE;
\r
2007 appData.animSpeed = 10;
\r
2008 appData.animateDragging = TRUE;
\r
2009 appData.highlightLastMove = TRUE;
\r
2010 appData.getMoveList = TRUE;
\r
2011 appData.testLegality = TRUE;
\r
2012 appData.premove = TRUE;
\r
2013 appData.premoveWhite = FALSE;
\r
2014 appData.premoveWhiteText = "";
\r
2015 appData.premoveBlack = FALSE;
\r
2016 appData.premoveBlackText = "";
\r
2017 appData.icsAlarm = TRUE;
\r
2018 appData.icsAlarmTime = 5000;
\r
2019 appData.autoRaiseBoard = TRUE;
\r
2020 appData.localLineEditing = TRUE;
\r
2021 appData.colorize = TRUE;
\r
2022 appData.reuseFirst = TRUE;
\r
2023 appData.reuseSecond = TRUE;
\r
2024 appData.blindfold = FALSE;
\r
2025 appData.icsEngineAnalyze = FALSE;
\r
2026 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2027 dcb.DCBlength = sizeof(DCB);
\r
2028 dcb.BaudRate = 9600;
\r
2029 dcb.fBinary = TRUE;
\r
2030 dcb.fParity = FALSE;
\r
2031 dcb.fOutxCtsFlow = FALSE;
\r
2032 dcb.fOutxDsrFlow = FALSE;
\r
2033 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2034 dcb.fDsrSensitivity = FALSE;
\r
2035 dcb.fTXContinueOnXoff = TRUE;
\r
2036 dcb.fOutX = FALSE;
\r
2038 dcb.fNull = FALSE;
\r
2039 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2040 dcb.fAbortOnError = FALSE;
\r
2042 dcb.Parity = SPACEPARITY;
\r
2043 dcb.StopBits = ONESTOPBIT;
\r
2044 settingsFileName = SETTINGS_FILE;
\r
2045 saveSettingsOnExit = TRUE;
\r
2046 boardX = CW_USEDEFAULT;
\r
2047 boardY = CW_USEDEFAULT;
\r
2048 analysisX = CW_USEDEFAULT;
\r
2049 analysisY = CW_USEDEFAULT;
\r
2050 analysisW = CW_USEDEFAULT;
\r
2051 analysisH = CW_USEDEFAULT;
\r
2052 commentX = CW_USEDEFAULT;
\r
2053 commentY = CW_USEDEFAULT;
\r
2054 commentW = CW_USEDEFAULT;
\r
2055 commentH = CW_USEDEFAULT;
\r
2056 editTagsX = CW_USEDEFAULT;
\r
2057 editTagsY = CW_USEDEFAULT;
\r
2058 editTagsW = CW_USEDEFAULT;
\r
2059 editTagsH = CW_USEDEFAULT;
\r
2060 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2061 icsNames = ICS_NAMES;
\r
2062 firstChessProgramNames = FCP_NAMES;
\r
2063 secondChessProgramNames = SCP_NAMES;
\r
2064 appData.initialMode = "";
\r
2065 appData.variant = "normal";
\r
2066 appData.firstProtocolVersion = PROTOVER;
\r
2067 appData.secondProtocolVersion = PROTOVER;
\r
2068 appData.showButtonBar = TRUE;
\r
2070 /* [AS] New properties (see comments in header file) */
\r
2071 appData.firstScoreIsAbsolute = FALSE;
\r
2072 appData.secondScoreIsAbsolute = FALSE;
\r
2073 appData.saveExtendedInfoInPGN = FALSE;
\r
2074 appData.hideThinkingFromHuman = FALSE;
\r
2075 appData.liteBackTextureFile = "";
\r
2076 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2077 appData.darkBackTextureFile = "";
\r
2078 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2079 appData.renderPiecesWithFont = "";
\r
2080 appData.fontToPieceTable = "";
\r
2081 appData.fontBackColorWhite = 0;
\r
2082 appData.fontForeColorWhite = 0;
\r
2083 appData.fontBackColorBlack = 0;
\r
2084 appData.fontForeColorBlack = 0;
\r
2085 appData.fontPieceSize = 80;
\r
2086 appData.overrideLineGap = 1;
\r
2087 appData.adjudicateLossThreshold = 0;
\r
2088 appData.delayBeforeQuit = 0;
\r
2089 appData.delayAfterQuit = 0;
\r
2090 appData.nameOfDebugFile = "winboard.debug";
\r
2091 appData.pgnEventHeader = "Computer Chess Game";
\r
2092 appData.defaultFrcPosition = -1;
\r
2093 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2094 appData.saveOutOfBookInfo = TRUE;
\r
2095 appData.showEvalInMoveHistory = TRUE;
\r
2096 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2097 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2098 appData.highlightMoveWithArrow = FALSE;
\r
2099 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2100 appData.useStickyWindows = TRUE;
\r
2101 appData.adjudicateDrawMoves = 0;
\r
2102 appData.autoDisplayComment = TRUE;
\r
2103 appData.autoDisplayTags = TRUE;
\r
2104 appData.firstIsUCI = FALSE;
\r
2105 appData.secondIsUCI = FALSE;
\r
2106 appData.firstHasOwnBookUCI = TRUE;
\r
2107 appData.secondHasOwnBookUCI = TRUE;
\r
2108 appData.polyglotDir = "";
\r
2109 appData.usePolyglotBook = FALSE;
\r
2110 appData.polyglotBook = "";
\r
2111 appData.defaultHashSize = 64;
\r
2112 appData.defaultCacheSizeEGTB = 4;
\r
2113 appData.defaultPathEGTB = "c:\\egtb";
\r
2114 appData.firstOptions = "";
\r
2115 appData.secondOptions = "";
\r
2117 InitWindowPlacement( &wpGameList );
\r
2118 InitWindowPlacement( &wpMoveHistory );
\r
2119 InitWindowPlacement( &wpEvalGraph );
\r
2120 InitWindowPlacement( &wpEngineOutput );
\r
2121 InitWindowPlacement( &wpConsole );
\r
2123 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2124 appData.NrFiles = -1;
\r
2125 appData.NrRanks = -1;
\r
2126 appData.holdingsSize = -1;
\r
2127 appData.testClaims = FALSE;
\r
2128 appData.checkMates = FALSE;
\r
2129 appData.materialDraws= FALSE;
\r
2130 appData.trivialDraws = FALSE;
\r
2131 appData.ruleMoves = 51;
\r
2132 appData.drawRepeats = 6;
\r
2133 appData.matchPause = 10000;
\r
2134 appData.alphaRank = FALSE;
\r
2135 appData.allWhite = FALSE;
\r
2136 appData.upsideDown = FALSE;
\r
2137 appData.serverPause = 15;
\r
2138 appData.serverMovesName = NULL;
\r
2139 appData.suppressLoadMoves = FALSE;
\r
2140 appData.firstTimeOdds = 1;
\r
2141 appData.secondTimeOdds = 1;
\r
2142 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2143 appData.secondAccumulateTC = 1;
\r
2144 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2145 appData.secondNPS = -1;
\r
2146 appData.engineComments = 1;
\r
2147 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2148 appData.egtFormats = "";
\r
2151 appData.zippyTalk = ZIPPY_TALK;
\r
2152 appData.zippyPlay = ZIPPY_PLAY;
\r
2153 appData.zippyLines = ZIPPY_LINES;
\r
2154 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2155 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2156 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2157 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2158 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2159 appData.zippyUseI = ZIPPY_USE_I;
\r
2160 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2161 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2162 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2163 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2164 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2165 appData.zippyAbort = ZIPPY_ABORT;
\r
2166 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2167 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2168 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2171 /* Point font array elements to structures and
\r
2172 parse default font names */
\r
2173 for (i=0; i<NUM_FONTS; i++) {
\r
2174 for (j=0; j<NUM_SIZES; j++) {
\r
2175 font[j][i] = &fontRec[j][i];
\r
2176 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2180 /* Parse default settings file if any */
\r
2181 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2182 settingsFileName = strdup(buf);
\r
2185 /* Parse command line */
\r
2186 ParseArgs(StringGet, &lpCmdLine);
\r
2188 /* [HGM] make sure board size is acceptable */
\r
2189 if(appData.NrFiles > BOARD_SIZE ||
\r
2190 appData.NrRanks > BOARD_SIZE )
\r
2191 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2193 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2194 * with options from the command line, we now make an even higher priority
\r
2195 * overrule by WB options attached to the engine command line. This so that
\r
2196 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2199 if(appData.firstChessProgram != NULL) {
\r
2200 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2201 static char *f = "first";
\r
2202 char buf[MSG_SIZ], *q = buf;
\r
2203 if(p != NULL) { // engine command line contains WinBoard options
\r
2204 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2205 ParseArgs(StringGet, &q);
\r
2206 p[-1] = 0; // cut them offengine command line
\r
2209 // now do same for second chess program
\r
2210 if(appData.secondChessProgram != NULL) {
\r
2211 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2212 static char *s = "second";
\r
2213 char buf[MSG_SIZ], *q = buf;
\r
2214 if(p != NULL) { // engine command line contains WinBoard options
\r
2215 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2216 ParseArgs(StringGet, &q);
\r
2217 p[-1] = 0; // cut them offengine command line
\r
2222 /* Propagate options that affect others */
\r
2223 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2224 if (appData.icsActive || appData.noChessProgram) {
\r
2225 chessProgram = FALSE; /* not local chess program mode */
\r
2228 /* Open startup dialog if needed */
\r
2229 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2230 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2231 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2232 *appData.secondChessProgram == NULLCHAR))) {
\r
2235 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2236 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2237 FreeProcInstance(lpProc);
\r
2240 /* Make sure save files land in the right (?) directory */
\r
2241 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2242 appData.saveGameFile = strdup(buf);
\r
2244 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.savePositionFile = strdup(buf);
\r
2248 /* Finish initialization for fonts and sounds */
\r
2249 for (i=0; i<NUM_FONTS; i++) {
\r
2250 for (j=0; j<NUM_SIZES; j++) {
\r
2251 CreateFontInMF(font[j][i]);
\r
2254 /* xboard, and older WinBoards, controlled the move sound with the
\r
2255 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2256 always turn the option on (so that the backend will call us),
\r
2257 then let the user turn the sound off by setting it to silence if
\r
2258 desired. To accommodate old winboard.ini files saved by old
\r
2259 versions of WinBoard, we also turn off the sound if the option
\r
2260 was initially set to false. */
\r
2261 if (!appData.ringBellAfterMoves) {
\r
2262 sounds[(int)SoundMove].name = strdup("");
\r
2263 appData.ringBellAfterMoves = TRUE;
\r
2265 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2266 SetCurrentDirectory(installDir);
\r
2268 SetCurrentDirectory(currDir);
\r
2270 p = icsTextMenuString;
\r
2271 if (p[0] == '@') {
\r
2272 FILE* f = fopen(p + 1, "r");
\r
2274 DisplayFatalError(p + 1, errno, 2);
\r
2277 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2279 buf[i] = NULLCHAR;
\r
2282 ParseIcsTextMenu(strdup(p));
\r
2289 HMENU hmenu = GetMenu(hwndMain);
\r
2291 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2292 MF_BYCOMMAND|((appData.icsActive &&
\r
2293 *appData.icsCommPort != NULLCHAR) ?
\r
2294 MF_ENABLED : MF_GRAYED));
\r
2295 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2296 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2297 MF_CHECKED : MF_UNCHECKED));
\r
2302 SaveSettings(char* name)
\r
2305 ArgDescriptor *ad;
\r
2306 WINDOWPLACEMENT wp;
\r
2307 char dir[MSG_SIZ];
\r
2309 if (!hwndMain) return;
\r
2311 GetCurrentDirectory(MSG_SIZ, dir);
\r
2312 SetCurrentDirectory(installDir);
\r
2313 f = fopen(name, "w");
\r
2314 SetCurrentDirectory(dir);
\r
2316 DisplayError(name, errno);
\r
2319 fprintf(f, ";\n");
\r
2320 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2321 fprintf(f, ";\n");
\r
2322 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2323 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2324 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2325 fprintf(f, ";\n");
\r
2327 wp.length = sizeof(WINDOWPLACEMENT);
\r
2328 GetWindowPlacement(hwndMain, &wp);
\r
2329 boardX = wp.rcNormalPosition.left;
\r
2330 boardY = wp.rcNormalPosition.top;
\r
2332 if (hwndConsole) {
\r
2333 GetWindowPlacement(hwndConsole, &wp);
\r
2334 wpConsole.x = wp.rcNormalPosition.left;
\r
2335 wpConsole.y = wp.rcNormalPosition.top;
\r
2336 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2337 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2340 if (analysisDialog) {
\r
2341 GetWindowPlacement(analysisDialog, &wp);
\r
2342 analysisX = wp.rcNormalPosition.left;
\r
2343 analysisY = wp.rcNormalPosition.top;
\r
2344 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2345 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2348 if (commentDialog) {
\r
2349 GetWindowPlacement(commentDialog, &wp);
\r
2350 commentX = wp.rcNormalPosition.left;
\r
2351 commentY = wp.rcNormalPosition.top;
\r
2352 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (editTagsDialog) {
\r
2357 GetWindowPlacement(editTagsDialog, &wp);
\r
2358 editTagsX = wp.rcNormalPosition.left;
\r
2359 editTagsY = wp.rcNormalPosition.top;
\r
2360 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (gameListDialog) {
\r
2365 GetWindowPlacement(gameListDialog, &wp);
\r
2366 wpGameList.x = wp.rcNormalPosition.left;
\r
2367 wpGameList.y = wp.rcNormalPosition.top;
\r
2368 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 /* [AS] Move history */
\r
2373 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2375 if( moveHistoryDialog ) {
\r
2376 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2377 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2378 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2379 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2380 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2383 /* [AS] Eval graph */
\r
2384 wpEvalGraph.visible = EvalGraphIsUp();
\r
2386 if( evalGraphDialog ) {
\r
2387 GetWindowPlacement(evalGraphDialog, &wp);
\r
2388 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2389 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2390 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2391 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2394 /* [AS] Engine output */
\r
2395 wpEngineOutput.visible = EngineOutputIsUp();
\r
2397 if( engineOutputDialog ) {
\r
2398 GetWindowPlacement(engineOutputDialog, &wp);
\r
2399 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2400 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2401 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2402 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2405 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2406 if (!ad->save) continue;
\r
2407 switch (ad->argType) {
\r
2410 char *p = *(char **)ad->argLoc;
\r
2411 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2412 /* Quote multiline values or \-containing values
\r
2413 with { } if possible */
\r
2414 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2416 /* Else quote with " " */
\r
2417 fprintf(f, "/%s=\"", ad->argName);
\r
2419 if (*p == '\n') fprintf(f, "\n");
\r
2420 else if (*p == '\r') fprintf(f, "\\r");
\r
2421 else if (*p == '\t') fprintf(f, "\\t");
\r
2422 else if (*p == '\b') fprintf(f, "\\b");
\r
2423 else if (*p == '\f') fprintf(f, "\\f");
\r
2424 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2425 else if (*p == '\"') fprintf(f, "\\\"");
\r
2426 else if (*p == '\\') fprintf(f, "\\\\");
\r
2430 fprintf(f, "\"\n");
\r
2436 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2445 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2448 fprintf(f, "/%s=%s\n", ad->argName,
\r
2449 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2452 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2455 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2460 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2461 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2466 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2467 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2468 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2469 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2470 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2471 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2472 (ta->effects) ? " " : "",
\r
2473 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2477 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2478 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2480 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2483 case ArgBoardSize:
\r
2484 fprintf(f, "/%s=%s\n", ad->argName,
\r
2485 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2490 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2491 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2492 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2493 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2494 ad->argName, mfp->faceName, mfp->pointSize,
\r
2495 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2496 mfp->bold ? "b" : "",
\r
2497 mfp->italic ? "i" : "",
\r
2498 mfp->underline ? "u" : "",
\r
2499 mfp->strikeout ? "s" : "");
\r
2503 case ArgCommSettings:
\r
2504 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2506 case ArgSettingsFilename: ;
\r
2514 /*---------------------------------------------------------------------------*\
\r
2516 * GDI board drawing routines
\r
2518 \*---------------------------------------------------------------------------*/
\r
2520 /* [AS] Draw square using background texture */
\r
2521 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2526 return; /* Should never happen! */
\r
2529 SetGraphicsMode( dst, GM_ADVANCED );
\r
2536 /* X reflection */
\r
2541 x.eDx = (FLOAT) dw + dx - 1;
\r
2544 SetWorldTransform( dst, &x );
\r
2547 /* Y reflection */
\r
2553 x.eDy = (FLOAT) dh + dy - 1;
\r
2555 SetWorldTransform( dst, &x );
\r
2563 x.eDx = (FLOAT) dx;
\r
2564 x.eDy = (FLOAT) dy;
\r
2567 SetWorldTransform( dst, &x );
\r
2571 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2579 SetWorldTransform( dst, &x );
\r
2581 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2584 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2586 PM_WP = (int) WhitePawn,
\r
2587 PM_WN = (int) WhiteKnight,
\r
2588 PM_WB = (int) WhiteBishop,
\r
2589 PM_WR = (int) WhiteRook,
\r
2590 PM_WQ = (int) WhiteQueen,
\r
2591 PM_WF = (int) WhiteFerz,
\r
2592 PM_WW = (int) WhiteWazir,
\r
2593 PM_WE = (int) WhiteAlfil,
\r
2594 PM_WM = (int) WhiteMan,
\r
2595 PM_WO = (int) WhiteCannon,
\r
2596 PM_WU = (int) WhiteUnicorn,
\r
2597 PM_WH = (int) WhiteNightrider,
\r
2598 PM_WA = (int) WhiteAngel,
\r
2599 PM_WC = (int) WhiteMarshall,
\r
2600 PM_WAB = (int) WhiteCardinal,
\r
2601 PM_WD = (int) WhiteDragon,
\r
2602 PM_WL = (int) WhiteLance,
\r
2603 PM_WS = (int) WhiteCobra,
\r
2604 PM_WV = (int) WhiteFalcon,
\r
2605 PM_WSG = (int) WhiteSilver,
\r
2606 PM_WG = (int) WhiteGrasshopper,
\r
2607 PM_WK = (int) WhiteKing,
\r
2608 PM_BP = (int) BlackPawn,
\r
2609 PM_BN = (int) BlackKnight,
\r
2610 PM_BB = (int) BlackBishop,
\r
2611 PM_BR = (int) BlackRook,
\r
2612 PM_BQ = (int) BlackQueen,
\r
2613 PM_BF = (int) BlackFerz,
\r
2614 PM_BW = (int) BlackWazir,
\r
2615 PM_BE = (int) BlackAlfil,
\r
2616 PM_BM = (int) BlackMan,
\r
2617 PM_BO = (int) BlackCannon,
\r
2618 PM_BU = (int) BlackUnicorn,
\r
2619 PM_BH = (int) BlackNightrider,
\r
2620 PM_BA = (int) BlackAngel,
\r
2621 PM_BC = (int) BlackMarshall,
\r
2622 PM_BG = (int) BlackGrasshopper,
\r
2623 PM_BAB = (int) BlackCardinal,
\r
2624 PM_BD = (int) BlackDragon,
\r
2625 PM_BL = (int) BlackLance,
\r
2626 PM_BS = (int) BlackCobra,
\r
2627 PM_BV = (int) BlackFalcon,
\r
2628 PM_BSG = (int) BlackSilver,
\r
2629 PM_BK = (int) BlackKing
\r
2632 static HFONT hPieceFont = NULL;
\r
2633 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2634 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2635 static int fontBitmapSquareSize = 0;
\r
2636 static char pieceToFontChar[(int) EmptySquare] =
\r
2637 { 'p', 'n', 'b', 'r', 'q',
\r
2638 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2639 'k', 'o', 'm', 'v', 't', 'w',
\r
2640 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2643 extern BOOL SetCharTable( char *table, const char * map );
\r
2644 /* [HGM] moved to backend.c */
\r
2646 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2649 BYTE r1 = GetRValue( color );
\r
2650 BYTE g1 = GetGValue( color );
\r
2651 BYTE b1 = GetBValue( color );
\r
2657 /* Create a uniform background first */
\r
2658 hbrush = CreateSolidBrush( color );
\r
2659 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject( hbrush );
\r
2664 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2665 int steps = squareSize / 2;
\r
2668 for( i=0; i<steps; i++ ) {
\r
2669 BYTE r = r1 - (r1-r2) * i / steps;
\r
2670 BYTE g = g1 - (g1-g2) * i / steps;
\r
2671 BYTE b = b1 - (b1-b2) * i / steps;
\r
2673 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2674 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2675 FillRect( hdc, &rc, hbrush );
\r
2676 DeleteObject(hbrush);
\r
2679 else if( mode == 2 ) {
\r
2680 /* Diagonal gradient, good more or less for every piece */
\r
2681 POINT triangle[3];
\r
2682 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2683 HBRUSH hbrush_old;
\r
2684 int steps = squareSize;
\r
2687 triangle[0].x = squareSize - steps;
\r
2688 triangle[0].y = squareSize;
\r
2689 triangle[1].x = squareSize;
\r
2690 triangle[1].y = squareSize;
\r
2691 triangle[2].x = squareSize;
\r
2692 triangle[2].y = squareSize - steps;
\r
2694 for( i=0; i<steps; i++ ) {
\r
2695 BYTE r = r1 - (r1-r2) * i / steps;
\r
2696 BYTE g = g1 - (g1-g2) * i / steps;
\r
2697 BYTE b = b1 - (b1-b2) * i / steps;
\r
2699 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2700 hbrush_old = SelectObject( hdc, hbrush );
\r
2701 Polygon( hdc, triangle, 3 );
\r
2702 SelectObject( hdc, hbrush_old );
\r
2703 DeleteObject(hbrush);
\r
2708 SelectObject( hdc, hpen );
\r
2713 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2714 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2715 piece: follow the steps as explained below.
\r
2717 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2721 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2725 int backColor = whitePieceColor;
\r
2726 int foreColor = blackPieceColor;
\r
2728 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2729 backColor = appData.fontBackColorWhite;
\r
2730 foreColor = appData.fontForeColorWhite;
\r
2732 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2733 backColor = appData.fontBackColorBlack;
\r
2734 foreColor = appData.fontForeColorBlack;
\r
2738 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2740 hbm_old = SelectObject( hdc, hbm );
\r
2744 rc.right = squareSize;
\r
2745 rc.bottom = squareSize;
\r
2747 /* Step 1: background is now black */
\r
2748 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2750 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2752 pt.x = (squareSize - sz.cx) / 2;
\r
2753 pt.y = (squareSize - sz.cy) / 2;
\r
2755 SetBkMode( hdc, TRANSPARENT );
\r
2756 SetTextColor( hdc, chroma );
\r
2757 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2758 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2760 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2761 /* Step 3: the area outside the piece is filled with white */
\r
2762 // FloodFill( hdc, 0, 0, chroma );
\r
2763 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2764 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2765 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2766 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2767 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2769 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2770 but if the start point is not inside the piece we're lost!
\r
2771 There should be a better way to do this... if we could create a region or path
\r
2772 from the fill operation we would be fine for example.
\r
2774 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2775 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2777 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2778 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2779 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2781 SelectObject( dc2, bm2 );
\r
2782 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2783 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2786 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 DeleteObject( bm2 );
\r
2792 SetTextColor( hdc, 0 );
\r
2794 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2795 draw the piece again in black for safety.
\r
2797 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2799 SelectObject( hdc, hbm_old );
\r
2801 if( hPieceMask[index] != NULL ) {
\r
2802 DeleteObject( hPieceMask[index] );
\r
2805 hPieceMask[index] = hbm;
\r
2808 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2810 SelectObject( hdc, hbm );
\r
2813 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2814 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2815 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2817 SelectObject( dc1, hPieceMask[index] );
\r
2818 SelectObject( dc2, bm2 );
\r
2819 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2820 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2823 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2824 the piece background and deletes (makes transparent) the rest.
\r
2825 Thanks to that mask, we are free to paint the background with the greates
\r
2826 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2827 We use this, to make gradients and give the pieces a "roundish" look.
\r
2829 SetPieceBackground( hdc, backColor, 2 );
\r
2830 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2834 DeleteObject( bm2 );
\r
2837 SetTextColor( hdc, foreColor );
\r
2838 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2840 SelectObject( hdc, hbm_old );
\r
2842 if( hPieceFace[index] != NULL ) {
\r
2843 DeleteObject( hPieceFace[index] );
\r
2846 hPieceFace[index] = hbm;
\r
2849 static int TranslatePieceToFontPiece( int piece )
\r
2879 case BlackMarshall:
\r
2883 case BlackNightrider:
\r
2889 case BlackUnicorn:
\r
2893 case BlackGrasshopper:
\r
2905 case BlackCardinal:
\r
2912 case WhiteMarshall:
\r
2916 case WhiteNightrider:
\r
2922 case WhiteUnicorn:
\r
2926 case WhiteGrasshopper:
\r
2938 case WhiteCardinal:
\r
2947 void CreatePiecesFromFont()
\r
2950 HDC hdc_window = NULL;
\r
2956 if( fontBitmapSquareSize < 0 ) {
\r
2957 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2961 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2962 fontBitmapSquareSize = -1;
\r
2966 if( fontBitmapSquareSize != squareSize ) {
\r
2967 hdc_window = GetDC( hwndMain );
\r
2968 hdc = CreateCompatibleDC( hdc_window );
\r
2970 if( hPieceFont != NULL ) {
\r
2971 DeleteObject( hPieceFont );
\r
2974 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2975 hPieceMask[i] = NULL;
\r
2976 hPieceFace[i] = NULL;
\r
2982 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2983 fontHeight = appData.fontPieceSize;
\r
2986 fontHeight = (fontHeight * squareSize) / 100;
\r
2988 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2990 lf.lfEscapement = 0;
\r
2991 lf.lfOrientation = 0;
\r
2992 lf.lfWeight = FW_NORMAL;
\r
2994 lf.lfUnderline = 0;
\r
2995 lf.lfStrikeOut = 0;
\r
2996 lf.lfCharSet = DEFAULT_CHARSET;
\r
2997 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2998 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2999 lf.lfQuality = PROOF_QUALITY;
\r
3000 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3001 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3002 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3004 hPieceFont = CreateFontIndirect( &lf );
\r
3006 if( hPieceFont == NULL ) {
\r
3007 fontBitmapSquareSize = -2;
\r
3010 /* Setup font-to-piece character table */
\r
3011 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3012 /* No (or wrong) global settings, try to detect the font */
\r
3013 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3015 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3017 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3018 /* DiagramTT* family */
\r
3019 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3021 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3022 /* Fairy symbols */
\r
3023 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3025 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3026 /* Good Companion (Some characters get warped as literal :-( */
\r
3027 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3028 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3029 SetCharTable(pieceToFontChar, s);
\r
3032 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3033 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3037 /* Create bitmaps */
\r
3038 hfont_old = SelectObject( hdc, hPieceFont );
\r
3039 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3040 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3043 SelectObject( hdc, hfont_old );
\r
3045 fontBitmapSquareSize = squareSize;
\r
3049 if( hdc != NULL ) {
\r
3053 if( hdc_window != NULL ) {
\r
3054 ReleaseDC( hwndMain, hdc_window );
\r
3059 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3063 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3064 if (gameInfo.event &&
\r
3065 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3066 strcmp(name, "k80s") == 0) {
\r
3067 strcpy(name, "tim");
\r
3069 return LoadBitmap(hinst, name);
\r
3073 /* Insert a color into the program's logical palette
\r
3074 structure. This code assumes the given color is
\r
3075 the result of the RGB or PALETTERGB macro, and it
\r
3076 knows how those macros work (which is documented).
\r
3079 InsertInPalette(COLORREF color)
\r
3081 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3083 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3084 DisplayFatalError("Too many colors", 0, 1);
\r
3085 pLogPal->palNumEntries--;
\r
3089 pe->peFlags = (char) 0;
\r
3090 pe->peRed = (char) (0xFF & color);
\r
3091 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3092 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3098 InitDrawingColors()
\r
3100 if (pLogPal == NULL) {
\r
3101 /* Allocate enough memory for a logical palette with
\r
3102 * PALETTESIZE entries and set the size and version fields
\r
3103 * of the logical palette structure.
\r
3105 pLogPal = (NPLOGPALETTE)
\r
3106 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3107 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3108 pLogPal->palVersion = 0x300;
\r
3110 pLogPal->palNumEntries = 0;
\r
3112 InsertInPalette(lightSquareColor);
\r
3113 InsertInPalette(darkSquareColor);
\r
3114 InsertInPalette(whitePieceColor);
\r
3115 InsertInPalette(blackPieceColor);
\r
3116 InsertInPalette(highlightSquareColor);
\r
3117 InsertInPalette(premoveHighlightColor);
\r
3119 /* create a logical color palette according the information
\r
3120 * in the LOGPALETTE structure.
\r
3122 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3124 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3125 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3126 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3127 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3128 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3129 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3130 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3131 /* [AS] Force rendering of the font-based pieces */
\r
3132 if( fontBitmapSquareSize > 0 ) {
\r
3133 fontBitmapSquareSize = 0;
\r
3139 BoardWidth(int boardSize, int n)
\r
3140 { /* [HGM] argument n added to allow different width and height */
\r
3141 int lineGap = sizeInfo[boardSize].lineGap;
\r
3143 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3144 lineGap = appData.overrideLineGap;
\r
3147 return (n + 1) * lineGap +
\r
3148 n * sizeInfo[boardSize].squareSize;
\r
3151 /* Respond to board resize by dragging edge */
\r
3153 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3155 BoardSize newSize = NUM_SIZES - 1;
\r
3156 static int recurse = 0;
\r
3157 if (IsIconic(hwndMain)) return;
\r
3158 if (recurse > 0) return;
\r
3160 while (newSize > 0) {
\r
3161 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3162 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3163 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3166 boardSize = newSize;
\r
3167 InitDrawingSizes(boardSize, flags);
\r
3174 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3176 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3177 ChessSquare piece;
\r
3178 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3180 SIZE clockSize, messageSize;
\r
3182 char buf[MSG_SIZ];
\r
3184 HMENU hmenu = GetMenu(hwndMain);
\r
3185 RECT crect, wrect, oldRect;
\r
3187 LOGBRUSH logbrush;
\r
3189 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3190 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3192 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3193 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3195 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3196 oldRect.top = boardY;
\r
3197 oldRect.right = boardX + winWidth;
\r
3198 oldRect.bottom = boardY + winHeight;
\r
3200 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3201 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3202 squareSize = sizeInfo[boardSize].squareSize;
\r
3203 lineGap = sizeInfo[boardSize].lineGap;
\r
3204 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3206 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3207 lineGap = appData.overrideLineGap;
\r
3210 if (tinyLayout != oldTinyLayout) {
\r
3211 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3213 style &= ~WS_SYSMENU;
\r
3214 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3215 "&Minimize\tCtrl+F4");
\r
3217 style |= WS_SYSMENU;
\r
3218 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3220 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3222 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3223 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3224 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3226 DrawMenuBar(hwndMain);
\r
3229 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3230 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3232 /* Get text area sizes */
\r
3233 hdc = GetDC(hwndMain);
\r
3234 if (appData.clockMode) {
\r
3235 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3237 sprintf(buf, "White");
\r
3239 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3240 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3241 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3242 str = "We only care about the height here";
\r
3243 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3244 SelectObject(hdc, oldFont);
\r
3245 ReleaseDC(hwndMain, hdc);
\r
3247 /* Compute where everything goes */
\r
3248 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3249 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3250 logoHeight = 2*clockSize.cy;
\r
3251 leftLogoRect.left = OUTER_MARGIN;
\r
3252 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3253 leftLogoRect.top = OUTER_MARGIN;
\r
3254 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3256 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3257 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3258 rightLogoRect.top = OUTER_MARGIN;
\r
3259 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3262 whiteRect.left = leftLogoRect.right;
\r
3263 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3264 whiteRect.top = OUTER_MARGIN;
\r
3265 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3267 blackRect.right = rightLogoRect.left;
\r
3268 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3269 blackRect.top = whiteRect.top;
\r
3270 blackRect.bottom = whiteRect.bottom;
\r
3272 whiteRect.left = OUTER_MARGIN;
\r
3273 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3274 whiteRect.top = OUTER_MARGIN;
\r
3275 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3277 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3278 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3279 blackRect.top = whiteRect.top;
\r
3280 blackRect.bottom = whiteRect.bottom;
\r
3283 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3284 if (appData.showButtonBar) {
\r
3285 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3286 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3288 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3290 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3291 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3293 boardRect.left = OUTER_MARGIN;
\r
3294 boardRect.right = boardRect.left + boardWidth;
\r
3295 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3296 boardRect.bottom = boardRect.top + boardHeight;
\r
3298 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3299 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3300 oldBoardSize = boardSize;
\r
3301 oldTinyLayout = tinyLayout;
\r
3302 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3303 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3304 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3305 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3306 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3307 winHeight = winH; // without disturbing window attachments
\r
3308 GetWindowRect(hwndMain, &wrect);
\r
3309 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3310 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3312 // [HGM] placement: let attached windows follow size change.
\r
3313 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3314 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3315 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3319 /* compensate if menu bar wrapped */
\r
3320 GetClientRect(hwndMain, &crect);
\r
3321 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3322 winHeight += offby;
\r
3324 case WMSZ_TOPLEFT:
\r
3325 SetWindowPos(hwndMain, NULL,
\r
3326 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3327 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3330 case WMSZ_TOPRIGHT:
\r
3332 SetWindowPos(hwndMain, NULL,
\r
3333 wrect.left, wrect.bottom - winHeight,
\r
3334 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3337 case WMSZ_BOTTOMLEFT:
\r
3339 SetWindowPos(hwndMain, NULL,
\r
3340 wrect.right - winWidth, wrect.top,
\r
3341 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3344 case WMSZ_BOTTOMRIGHT:
\r
3348 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3349 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3354 for (i = 0; i < N_BUTTONS; i++) {
\r
3355 if (buttonDesc[i].hwnd != NULL) {
\r
3356 DestroyWindow(buttonDesc[i].hwnd);
\r
3357 buttonDesc[i].hwnd = NULL;
\r
3359 if (appData.showButtonBar) {
\r
3360 buttonDesc[i].hwnd =
\r
3361 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3362 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3363 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3364 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3365 (HMENU) buttonDesc[i].id,
\r
3366 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3368 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3369 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3370 MAKELPARAM(FALSE, 0));
\r
3372 if (buttonDesc[i].id == IDM_Pause)
\r
3373 hwndPause = buttonDesc[i].hwnd;
\r
3374 buttonDesc[i].wndproc = (WNDPROC)
\r
3375 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3378 if (gridPen != NULL) DeleteObject(gridPen);
\r
3379 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3380 if (premovePen != NULL) DeleteObject(premovePen);
\r
3381 if (lineGap != 0) {
\r
3382 logbrush.lbStyle = BS_SOLID;
\r
3383 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3385 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3386 lineGap, &logbrush, 0, NULL);
\r
3387 logbrush.lbColor = highlightSquareColor;
\r
3389 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3390 lineGap, &logbrush, 0, NULL);
\r
3392 logbrush.lbColor = premoveHighlightColor;
\r
3394 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3395 lineGap, &logbrush, 0, NULL);
\r
3397 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3398 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3399 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3400 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3401 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3402 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3403 BOARD_WIDTH * (squareSize + lineGap);
\r
3404 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3406 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3407 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3408 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3409 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3410 lineGap / 2 + (i * (squareSize + lineGap));
\r
3411 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3412 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3413 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3417 /* [HGM] Licensing requirement */
\r
3419 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3422 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3424 GothicPopUp( "", VariantNormal);
\r
3427 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3429 /* Load piece bitmaps for this board size */
\r
3430 for (i=0; i<=2; i++) {
\r
3431 for (piece = WhitePawn;
\r
3432 (int) piece < (int) BlackPawn;
\r
3433 piece = (ChessSquare) ((int) piece + 1)) {
\r
3434 if (pieceBitmap[i][piece] != NULL)
\r
3435 DeleteObject(pieceBitmap[i][piece]);
\r
3439 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3440 // Orthodox Chess pieces
\r
3441 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3442 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3443 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3444 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3446 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3451 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3452 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3454 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3456 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3457 // in Shogi, Hijack the unused Queen for Lance
\r
3458 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3459 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3460 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3462 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3463 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3464 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3467 if(squareSize <= 72 && squareSize >= 33) {
\r
3468 /* A & C are available in most sizes now */
\r
3469 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3470 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3482 } else { // Smirf-like
\r
3483 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3487 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3488 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3491 } else { // WinBoard standard
\r
3492 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3499 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3500 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3515 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3531 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3532 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3559 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3560 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3561 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3562 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3563 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3564 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3565 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3566 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3567 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3568 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3569 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3570 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3577 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3578 /* special Shogi support in this size */
\r
3579 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3580 for (piece = WhitePawn;
\r
3581 (int) piece < (int) BlackPawn;
\r
3582 piece = (ChessSquare) ((int) piece + 1)) {
\r
3583 if (pieceBitmap[i][piece] != NULL)
\r
3584 DeleteObject(pieceBitmap[i][piece]);
\r
3587 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3588 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3589 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3590 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3601 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3602 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3603 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3604 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3615 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3616 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3617 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3618 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3634 PieceBitmap(ChessSquare p, int kind)
\r
3636 if ((int) p >= (int) BlackPawn)
\r
3637 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3639 return pieceBitmap[kind][(int) p];
\r
3642 /***************************************************************/
\r
3644 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3645 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3647 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3648 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3652 SquareToPos(int row, int column, int * x, int * y)
\r
3655 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3656 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3658 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3659 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3664 DrawCoordsOnDC(HDC hdc)
\r
3666 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3667 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3668 char str[2] = { NULLCHAR, NULLCHAR };
\r
3669 int oldMode, oldAlign, x, y, start, i;
\r
3673 if (!appData.showCoords)
\r
3676 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3678 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3679 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3680 oldAlign = GetTextAlign(hdc);
\r
3681 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3683 y = boardRect.top + lineGap;
\r
3684 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3686 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3687 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3688 str[0] = files[start + i];
\r
3689 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3690 y += squareSize + lineGap;
\r
3693 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3695 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3696 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3697 str[0] = ranks[start + i];
\r
3698 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3699 x += squareSize + lineGap;
\r
3702 SelectObject(hdc, oldBrush);
\r
3703 SetBkMode(hdc, oldMode);
\r
3704 SetTextAlign(hdc, oldAlign);
\r
3705 SelectObject(hdc, oldFont);
\r
3709 DrawGridOnDC(HDC hdc)
\r
3713 if (lineGap != 0) {
\r
3714 oldPen = SelectObject(hdc, gridPen);
\r
3715 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3716 SelectObject(hdc, oldPen);
\r
3720 #define HIGHLIGHT_PEN 0
\r
3721 #define PREMOVE_PEN 1
\r
3724 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3727 HPEN oldPen, hPen;
\r
3728 if (lineGap == 0) return;
\r
3730 x1 = boardRect.left +
\r
3731 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3732 y1 = boardRect.top +
\r
3733 lineGap/2 + y * (squareSize + lineGap);
\r
3735 x1 = boardRect.left +
\r
3736 lineGap/2 + x * (squareSize + lineGap);
\r
3737 y1 = boardRect.top +
\r
3738 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3740 hPen = pen ? premovePen : highlightPen;
\r
3741 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3742 MoveToEx(hdc, x1, y1, NULL);
\r
3743 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3744 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3745 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3746 LineTo(hdc, x1, y1);
\r
3747 SelectObject(hdc, oldPen);
\r
3751 DrawHighlightsOnDC(HDC hdc)
\r
3754 for (i=0; i<2; i++) {
\r
3755 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3756 DrawHighlightOnDC(hdc, TRUE,
\r
3757 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3760 for (i=0; i<2; i++) {
\r
3761 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3762 premoveHighlightInfo.sq[i].y >= 0) {
\r
3763 DrawHighlightOnDC(hdc, TRUE,
\r
3764 premoveHighlightInfo.sq[i].x,
\r
3765 premoveHighlightInfo.sq[i].y,
\r
3771 /* Note: sqcolor is used only in monoMode */
\r
3772 /* Note that this code is largely duplicated in woptions.c,
\r
3773 function DrawSampleSquare, so that needs to be updated too */
\r
3775 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3777 HBITMAP oldBitmap;
\r
3781 if (appData.blindfold) return;
\r
3783 /* [AS] Use font-based pieces if needed */
\r
3784 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3785 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3786 CreatePiecesFromFont();
\r
3788 if( fontBitmapSquareSize == squareSize ) {
\r
3789 int index = TranslatePieceToFontPiece(piece);
\r
3791 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3795 squareSize, squareSize,
\r
3800 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3804 squareSize, squareSize,
\r
3813 if (appData.monoMode) {
\r
3814 SelectObject(tmphdc, PieceBitmap(piece,
\r
3815 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3816 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3817 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3819 tmpSize = squareSize;
\r
3821 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3822 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3823 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3824 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3825 x += (squareSize - minorSize)>>1;
\r
3826 y += squareSize - minorSize - 2;
\r
3827 tmpSize = minorSize;
\r
3829 if (color || appData.allWhite ) {
\r
3830 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3832 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3833 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3834 if(appData.upsideDown && color==flipView)
\r
3835 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3837 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3838 /* Use black for outline of white pieces */
\r
3839 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3840 if(appData.upsideDown && color==flipView)
\r
3841 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3843 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3845 /* Use square color for details of black pieces */
\r
3846 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3847 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3848 if(appData.upsideDown && !flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3853 SelectObject(hdc, oldBrush);
\r
3854 SelectObject(tmphdc, oldBitmap);
\r
3858 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3859 int GetBackTextureMode( int algo )
\r
3861 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3865 case BACK_TEXTURE_MODE_PLAIN:
\r
3866 result = 1; /* Always use identity map */
\r
3868 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3869 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3877 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3878 to handle redraws cleanly (as random numbers would always be different).
\r
3880 VOID RebuildTextureSquareInfo()
\r
3890 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3892 if( liteBackTexture != NULL ) {
\r
3893 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3894 lite_w = bi.bmWidth;
\r
3895 lite_h = bi.bmHeight;
\r
3899 if( darkBackTexture != NULL ) {
\r
3900 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3901 dark_w = bi.bmWidth;
\r
3902 dark_h = bi.bmHeight;
\r
3906 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3907 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3908 if( (col + row) & 1 ) {
\r
3910 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3911 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3912 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3913 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3918 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3928 /* [AS] Arrow highlighting support */
\r
3930 static int A_WIDTH = 5; /* Width of arrow body */
\r
3932 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3933 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3935 static double Sqr( double x )
\r
3940 static int Round( double x )
\r
3942 return (int) (x + 0.5);
\r
3945 /* Draw an arrow between two points using current settings */
\r
3946 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3949 double dx, dy, j, k, x, y;
\r
3951 if( d_x == s_x ) {
\r
3952 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3954 arrow[0].x = s_x + A_WIDTH;
\r
3957 arrow[1].x = s_x + A_WIDTH;
\r
3958 arrow[1].y = d_y - h;
\r
3960 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3961 arrow[2].y = d_y - h;
\r
3966 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3967 arrow[4].y = d_y - h;
\r
3969 arrow[5].x = s_x - A_WIDTH;
\r
3970 arrow[5].y = d_y - h;
\r
3972 arrow[6].x = s_x - A_WIDTH;
\r
3975 else if( d_y == s_y ) {
\r
3976 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3979 arrow[0].y = s_y + A_WIDTH;
\r
3981 arrow[1].x = d_x - w;
\r
3982 arrow[1].y = s_y + A_WIDTH;
\r
3984 arrow[2].x = d_x - w;
\r
3985 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3990 arrow[4].x = d_x - w;
\r
3991 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3993 arrow[5].x = d_x - w;
\r
3994 arrow[5].y = s_y - A_WIDTH;
\r
3997 arrow[6].y = s_y - A_WIDTH;
\r
4000 /* [AS] Needed a lot of paper for this! :-) */
\r
4001 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4002 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4004 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4006 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4011 arrow[0].x = Round(x - j);
\r
4012 arrow[0].y = Round(y + j*dx);
\r
4014 arrow[1].x = Round(x + j);
\r
4015 arrow[1].y = Round(y - j*dx);
\r
4018 x = (double) d_x - k;
\r
4019 y = (double) d_y - k*dy;
\r
4022 x = (double) d_x + k;
\r
4023 y = (double) d_y + k*dy;
\r
4026 arrow[2].x = Round(x + j);
\r
4027 arrow[2].y = Round(y - j*dx);
\r
4029 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4030 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4035 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4036 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4038 arrow[6].x = Round(x - j);
\r
4039 arrow[6].y = Round(y + j*dx);
\r
4042 Polygon( hdc, arrow, 7 );
\r
4045 /* [AS] Draw an arrow between two squares */
\r
4046 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4048 int s_x, s_y, d_x, d_y;
\r
4055 if( s_col == d_col && s_row == d_row ) {
\r
4059 /* Get source and destination points */
\r
4060 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4061 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4064 d_y += squareSize / 4;
\r
4066 else if( d_y < s_y ) {
\r
4067 d_y += 3 * squareSize / 4;
\r
4070 d_y += squareSize / 2;
\r
4074 d_x += squareSize / 4;
\r
4076 else if( d_x < s_x ) {
\r
4077 d_x += 3 * squareSize / 4;
\r
4080 d_x += squareSize / 2;
\r
4083 s_x += squareSize / 2;
\r
4084 s_y += squareSize / 2;
\r
4086 /* Adjust width */
\r
4087 A_WIDTH = squareSize / 14;
\r
4090 stLB.lbStyle = BS_SOLID;
\r
4091 stLB.lbColor = appData.highlightArrowColor;
\r
4094 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4095 holdpen = SelectObject( hdc, hpen );
\r
4096 hbrush = CreateBrushIndirect( &stLB );
\r
4097 holdbrush = SelectObject( hdc, hbrush );
\r
4099 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4101 SelectObject( hdc, holdpen );
\r
4102 SelectObject( hdc, holdbrush );
\r
4103 DeleteObject( hpen );
\r
4104 DeleteObject( hbrush );
\r
4107 BOOL HasHighlightInfo()
\r
4109 BOOL result = FALSE;
\r
4111 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4112 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4120 BOOL IsDrawArrowEnabled()
\r
4122 BOOL result = FALSE;
\r
4124 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4131 VOID DrawArrowHighlight( HDC hdc )
\r
4133 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4134 DrawArrowBetweenSquares( hdc,
\r
4135 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4136 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4140 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4142 HRGN result = NULL;
\r
4144 if( HasHighlightInfo() ) {
\r
4145 int x1, y1, x2, y2;
\r
4146 int sx, sy, dx, dy;
\r
4148 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4149 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4151 sx = MIN( x1, x2 );
\r
4152 sy = MIN( y1, y2 );
\r
4153 dx = MAX( x1, x2 ) + squareSize;
\r
4154 dy = MAX( y1, y2 ) + squareSize;
\r
4156 result = CreateRectRgn( sx, sy, dx, dy );
\r
4163 Warning: this function modifies the behavior of several other functions.
\r
4165 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4166 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4167 repaint is scattered all over the place, which is not good for features such as
\r
4168 "arrow highlighting" that require a full repaint of the board.
\r
4170 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4171 user interaction, when speed is not so important) but especially to avoid errors
\r
4172 in the displayed graphics.
\r
4174 In such patched places, I always try refer to this function so there is a single
\r
4175 place to maintain knowledge.
\r
4177 To restore the original behavior, just return FALSE unconditionally.
\r
4179 BOOL IsFullRepaintPreferrable()
\r
4181 BOOL result = FALSE;
\r
4183 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4184 /* Arrow may appear on the board */
\r
4192 This function is called by DrawPosition to know whether a full repaint must
\r
4195 Only DrawPosition may directly call this function, which makes use of
\r
4196 some state information. Other function should call DrawPosition specifying
\r
4197 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4199 BOOL DrawPositionNeedsFullRepaint()
\r
4201 BOOL result = FALSE;
\r
4204 Probably a slightly better policy would be to trigger a full repaint
\r
4205 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4206 but animation is fast enough that it's difficult to notice.
\r
4208 if( animInfo.piece == EmptySquare ) {
\r
4209 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4218 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4220 int row, column, x, y, square_color, piece_color;
\r
4221 ChessSquare piece;
\r
4223 HDC texture_hdc = NULL;
\r
4225 /* [AS] Initialize background textures if needed */
\r
4226 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4227 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4228 if( backTextureSquareSize != squareSize
\r
4229 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4230 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4231 backTextureSquareSize = squareSize;
\r
4232 RebuildTextureSquareInfo();
\r
4235 texture_hdc = CreateCompatibleDC( hdc );
\r
4238 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4239 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4241 SquareToPos(row, column, &x, &y);
\r
4243 piece = board[row][column];
\r
4245 square_color = ((column + row) % 2) == 1;
\r
4246 if( gameInfo.variant == VariantXiangqi ) {
\r
4247 square_color = !InPalace(row, column);
\r
4248 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4249 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4251 piece_color = (int) piece < (int) BlackPawn;
\r
4254 /* [HGM] holdings file: light square or black */
\r
4255 if(column == BOARD_LEFT-2) {
\r
4256 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4259 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4263 if(column == BOARD_RGHT + 1 ) {
\r
4264 if( row < gameInfo.holdingsSize )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4271 if(column == BOARD_LEFT-1 ) /* left align */
\r
4272 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4273 else if( column == BOARD_RGHT) /* right align */
\r
4274 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4276 if (appData.monoMode) {
\r
4277 if (piece == EmptySquare) {
\r
4278 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4279 square_color ? WHITENESS : BLACKNESS);
\r
4281 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4284 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4285 /* [AS] Draw the square using a texture bitmap */
\r
4286 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4287 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4288 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4291 squareSize, squareSize,
\r
4294 backTextureSquareInfo[r][c].mode,
\r
4295 backTextureSquareInfo[r][c].x,
\r
4296 backTextureSquareInfo[r][c].y );
\r
4298 SelectObject( texture_hdc, hbm );
\r
4300 if (piece != EmptySquare) {
\r
4301 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4305 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4307 oldBrush = SelectObject(hdc, brush );
\r
4308 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4309 SelectObject(hdc, oldBrush);
\r
4310 if (piece != EmptySquare)
\r
4311 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4316 if( texture_hdc != NULL ) {
\r
4317 DeleteDC( texture_hdc );
\r
4321 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4322 void fputDW(FILE *f, int x)
\r
4324 fputc(x & 255, f);
\r
4325 fputc(x>>8 & 255, f);
\r
4326 fputc(x>>16 & 255, f);
\r
4327 fputc(x>>24 & 255, f);
\r
4330 #define MAX_CLIPS 200 /* more than enough */
\r
4333 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4335 // HBITMAP bufferBitmap;
\r
4340 int w = 100, h = 50;
\r
4342 if(logo == NULL) return;
\r
4343 // GetClientRect(hwndMain, &Rect);
\r
4344 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4345 // Rect.bottom-Rect.top+1);
\r
4346 tmphdc = CreateCompatibleDC(hdc);
\r
4347 hbm = SelectObject(tmphdc, logo);
\r
4348 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4352 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4353 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4354 SelectObject(tmphdc, hbm);
\r
4359 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4361 static Board lastReq, lastDrawn;
\r
4362 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4363 static int lastDrawnFlipView = 0;
\r
4364 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4365 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4368 HBITMAP bufferBitmap;
\r
4369 HBITMAP oldBitmap;
\r
4371 HRGN clips[MAX_CLIPS];
\r
4372 ChessSquare dragged_piece = EmptySquare;
\r
4374 /* I'm undecided on this - this function figures out whether a full
\r
4375 * repaint is necessary on its own, so there's no real reason to have the
\r
4376 * caller tell it that. I think this can safely be set to FALSE - but
\r
4377 * if we trust the callers not to request full repaints unnessesarily, then
\r
4378 * we could skip some clipping work. In other words, only request a full
\r
4379 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4380 * gamestart and similar) --Hawk
\r
4382 Boolean fullrepaint = repaint;
\r
4384 if( DrawPositionNeedsFullRepaint() ) {
\r
4385 fullrepaint = TRUE;
\r
4388 if (board == NULL) {
\r
4389 if (!lastReqValid) {
\r
4394 CopyBoard(lastReq, board);
\r
4398 if (doingSizing) {
\r
4402 if (IsIconic(hwndMain)) {
\r
4406 if (hdc == NULL) {
\r
4407 hdc = GetDC(hwndMain);
\r
4408 if (!appData.monoMode) {
\r
4409 SelectPalette(hdc, hPal, FALSE);
\r
4410 RealizePalette(hdc);
\r
4414 releaseDC = FALSE;
\r
4417 /* Create some work-DCs */
\r
4418 hdcmem = CreateCompatibleDC(hdc);
\r
4419 tmphdc = CreateCompatibleDC(hdc);
\r
4421 /* If dragging is in progress, we temporarely remove the piece */
\r
4422 /* [HGM] or temporarily decrease count if stacked */
\r
4423 /* !! Moved to before board compare !! */
\r
4424 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4425 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4426 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4427 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4428 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4430 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4431 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4432 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4434 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4437 /* Figure out which squares need updating by comparing the
\r
4438 * newest board with the last drawn board and checking if
\r
4439 * flipping has changed.
\r
4441 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4442 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4443 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4444 if (lastDrawn[row][column] != board[row][column]) {
\r
4445 SquareToPos(row, column, &x, &y);
\r
4446 clips[num_clips++] =
\r
4447 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4451 for (i=0; i<2; i++) {
\r
4452 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4453 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4454 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4455 lastDrawnHighlight.sq[i].y >= 0) {
\r
4456 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4457 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4458 clips[num_clips++] =
\r
4459 CreateRectRgn(x - lineGap, y - lineGap,
\r
4460 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4462 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4463 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4464 clips[num_clips++] =
\r
4465 CreateRectRgn(x - lineGap, y - lineGap,
\r
4466 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 for (i=0; i<2; i++) {
\r
4471 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4472 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4473 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4474 lastDrawnPremove.sq[i].y >= 0) {
\r
4475 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4476 lastDrawnPremove.sq[i].x, &x, &y);
\r
4477 clips[num_clips++] =
\r
4478 CreateRectRgn(x - lineGap, y - lineGap,
\r
4479 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4481 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4482 premoveHighlightInfo.sq[i].y >= 0) {
\r
4483 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4484 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4492 fullrepaint = TRUE;
\r
4495 /* Create a buffer bitmap - this is the actual bitmap
\r
4496 * being written to. When all the work is done, we can
\r
4497 * copy it to the real DC (the screen). This avoids
\r
4498 * the problems with flickering.
\r
4500 GetClientRect(hwndMain, &Rect);
\r
4501 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4502 Rect.bottom-Rect.top+1);
\r
4503 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4504 if (!appData.monoMode) {
\r
4505 SelectPalette(hdcmem, hPal, FALSE);
\r
4508 /* Create clips for dragging */
\r
4509 if (!fullrepaint) {
\r
4510 if (dragInfo.from.x >= 0) {
\r
4511 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4512 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4514 if (dragInfo.start.x >= 0) {
\r
4515 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4516 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4518 if (dragInfo.pos.x >= 0) {
\r
4519 x = dragInfo.pos.x - squareSize / 2;
\r
4520 y = dragInfo.pos.y - squareSize / 2;
\r
4521 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4523 if (dragInfo.lastpos.x >= 0) {
\r
4524 x = dragInfo.lastpos.x - squareSize / 2;
\r
4525 y = dragInfo.lastpos.y - squareSize / 2;
\r
4526 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4530 /* Are we animating a move?
\r
4532 * - remove the piece from the board (temporarely)
\r
4533 * - calculate the clipping region
\r
4535 if (!fullrepaint) {
\r
4536 if (animInfo.piece != EmptySquare) {
\r
4537 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4538 x = boardRect.left + animInfo.lastpos.x;
\r
4539 y = boardRect.top + animInfo.lastpos.y;
\r
4540 x2 = boardRect.left + animInfo.pos.x;
\r
4541 y2 = boardRect.top + animInfo.pos.y;
\r
4542 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4543 /* Slight kludge. The real problem is that after AnimateMove is
\r
4544 done, the position on the screen does not match lastDrawn.
\r
4545 This currently causes trouble only on e.p. captures in
\r
4546 atomic, where the piece moves to an empty square and then
\r
4547 explodes. The old and new positions both had an empty square
\r
4548 at the destination, but animation has drawn a piece there and
\r
4549 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4550 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4554 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4555 if (num_clips == 0)
\r
4556 fullrepaint = TRUE;
\r
4558 /* Set clipping on the memory DC */
\r
4559 if (!fullrepaint) {
\r
4560 SelectClipRgn(hdcmem, clips[0]);
\r
4561 for (x = 1; x < num_clips; x++) {
\r
4562 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4563 abort(); // this should never ever happen!
\r
4567 /* Do all the drawing to the memory DC */
\r
4568 if(explodeInfo.radius) { // [HGM] atomic
\r
4570 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4571 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4572 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4573 x += squareSize/2;
\r
4574 y += squareSize/2;
\r
4575 if(!fullrepaint) {
\r
4576 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4577 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4579 DrawGridOnDC(hdcmem);
\r
4580 DrawHighlightsOnDC(hdcmem);
\r
4581 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4582 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4583 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4584 SelectObject(hdcmem, oldBrush);
\r
4586 DrawGridOnDC(hdcmem);
\r
4587 DrawHighlightsOnDC(hdcmem);
\r
4588 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4591 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4592 if(appData.autoLogo) {
\r
4594 switch(gameMode) { // pick logos based on game mode
\r
4595 case IcsObserving:
\r
4596 whiteLogo = second.programLogo; // ICS logo
\r
4597 blackLogo = second.programLogo;
\r
4600 case IcsPlayingWhite:
\r
4601 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4602 blackLogo = second.programLogo; // ICS logo
\r
4604 case IcsPlayingBlack:
\r
4605 whiteLogo = second.programLogo; // ICS logo
\r
4606 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4608 case TwoMachinesPlay:
\r
4609 if(first.twoMachinesColor[0] == 'b') {
\r
4610 whiteLogo = second.programLogo;
\r
4611 blackLogo = first.programLogo;
\r
4614 case MachinePlaysWhite:
\r
4615 blackLogo = userLogo;
\r
4617 case MachinePlaysBlack:
\r
4618 whiteLogo = userLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4623 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4626 if( appData.highlightMoveWithArrow ) {
\r
4627 DrawArrowHighlight(hdcmem);
\r
4630 DrawCoordsOnDC(hdcmem);
\r
4632 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4633 /* to make sure lastDrawn contains what is actually drawn */
\r
4635 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4636 if (dragged_piece != EmptySquare) {
\r
4637 /* [HGM] or restack */
\r
4638 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4639 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4641 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4642 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4643 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4644 x = dragInfo.pos.x - squareSize / 2;
\r
4645 y = dragInfo.pos.y - squareSize / 2;
\r
4646 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4647 ((int) dragged_piece < (int) BlackPawn),
\r
4648 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4651 /* Put the animated piece back into place and draw it */
\r
4652 if (animInfo.piece != EmptySquare) {
\r
4653 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4654 x = boardRect.left + animInfo.pos.x;
\r
4655 y = boardRect.top + animInfo.pos.y;
\r
4656 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4657 ((int) animInfo.piece < (int) BlackPawn),
\r
4658 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4661 /* Release the bufferBitmap by selecting in the old bitmap
\r
4662 * and delete the memory DC
\r
4664 SelectObject(hdcmem, oldBitmap);
\r
4667 /* Set clipping on the target DC */
\r
4668 if (!fullrepaint) {
\r
4669 SelectClipRgn(hdc, clips[0]);
\r
4670 for (x = 1; x < num_clips; x++) {
\r
4671 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4672 abort(); // this should never ever happen!
\r
4676 /* Copy the new bitmap onto the screen in one go.
\r
4677 * This way we avoid any flickering
\r
4679 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4680 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4681 boardRect.right - boardRect.left,
\r
4682 boardRect.bottom - boardRect.top,
\r
4683 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4684 if(saveDiagFlag) {
\r
4685 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4686 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4688 GetObject(bufferBitmap, sizeof(b), &b);
\r
4689 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4690 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4691 bih.biWidth = b.bmWidth;
\r
4692 bih.biHeight = b.bmHeight;
\r
4694 bih.biBitCount = b.bmBitsPixel;
\r
4695 bih.biCompression = 0;
\r
4696 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4697 bih.biXPelsPerMeter = 0;
\r
4698 bih.biYPelsPerMeter = 0;
\r
4699 bih.biClrUsed = 0;
\r
4700 bih.biClrImportant = 0;
\r
4701 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4702 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4703 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4704 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4706 wb = b.bmWidthBytes;
\r
4708 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4709 int k = ((int*) pData)[i];
\r
4710 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4711 if(j >= 16) break;
\r
4713 if(j >= nrColors) nrColors = j+1;
\r
4715 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4717 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4718 for(w=0; w<(wb>>2); w+=2) {
\r
4719 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4720 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4721 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4722 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4723 pData[p++] = m | j<<4;
\r
4725 while(p&3) pData[p++] = 0;
\r
4728 wb = ((wb+31)>>5)<<2;
\r
4730 // write BITMAPFILEHEADER
\r
4731 fprintf(diagFile, "BM");
\r
4732 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4733 fputDW(diagFile, 0);
\r
4734 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4735 // write BITMAPINFOHEADER
\r
4736 fputDW(diagFile, 40);
\r
4737 fputDW(diagFile, b.bmWidth);
\r
4738 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4739 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4740 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 // write color table
\r
4749 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4750 // write bitmap data
\r
4751 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4752 fputc(pData[i], diagFile);
\r
4756 SelectObject(tmphdc, oldBitmap);
\r
4758 /* Massive cleanup */
\r
4759 for (x = 0; x < num_clips; x++)
\r
4760 DeleteObject(clips[x]);
\r
4763 DeleteObject(bufferBitmap);
\r
4766 ReleaseDC(hwndMain, hdc);
\r
4768 if (lastDrawnFlipView != flipView) {
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4775 /* CopyBoard(lastDrawn, board);*/
\r
4776 lastDrawnHighlight = highlightInfo;
\r
4777 lastDrawnPremove = premoveHighlightInfo;
\r
4778 lastDrawnFlipView = flipView;
\r
4779 lastDrawnValid = 1;
\r
4782 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4787 saveDiagFlag = 1; diagFile = f;
\r
4788 HDCDrawPosition(NULL, TRUE, NULL);
\r
4792 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4799 /*---------------------------------------------------------------------------*\
\r
4800 | CLIENT PAINT PROCEDURE
\r
4801 | This is the main event-handler for the WM_PAINT message.
\r
4803 \*---------------------------------------------------------------------------*/
\r
4805 PaintProc(HWND hwnd)
\r
4811 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4812 if (IsIconic(hwnd)) {
\r
4813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4815 if (!appData.monoMode) {
\r
4816 SelectPalette(hdc, hPal, FALSE);
\r
4817 RealizePalette(hdc);
\r
4819 HDCDrawPosition(hdc, 1, NULL);
\r
4821 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4822 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4823 ETO_CLIPPED|ETO_OPAQUE,
\r
4824 &messageRect, messageText, strlen(messageText), NULL);
\r
4825 SelectObject(hdc, oldFont);
\r
4826 DisplayBothClocks();
\r
4828 EndPaint(hwnd,&ps);
\r
4836 * If the user selects on a border boundary, return -1; if off the board,
\r
4837 * return -2. Otherwise map the event coordinate to the square.
\r
4838 * The offset boardRect.left or boardRect.top must already have been
\r
4839 * subtracted from x.
\r
4842 EventToSquare(int x)
\r
4849 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4851 x /= (squareSize + lineGap);
\r
4852 if (x >= BOARD_SIZE)
\r
4863 DropEnable dropEnables[] = {
\r
4864 { 'P', DP_Pawn, "Pawn" },
\r
4865 { 'N', DP_Knight, "Knight" },
\r
4866 { 'B', DP_Bishop, "Bishop" },
\r
4867 { 'R', DP_Rook, "Rook" },
\r
4868 { 'Q', DP_Queen, "Queen" },
\r
4872 SetupDropMenu(HMENU hmenu)
\r
4874 int i, count, enable;
\r
4876 extern char white_holding[], black_holding[];
\r
4877 char item[MSG_SIZ];
\r
4879 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4880 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4881 dropEnables[i].piece);
\r
4883 while (p && *p++ == dropEnables[i].piece) count++;
\r
4884 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4885 enable = count > 0 || !appData.testLegality
\r
4886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4887 && !appData.icsActive);
\r
4888 ModifyMenu(hmenu, dropEnables[i].command,
\r
4889 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4890 dropEnables[i].command, item);
\r
4894 /* Event handler for mouse messages */
\r
4896 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4900 static int recursive = 0;
\r
4902 // BOOLEAN needsRedraw = FALSE;
\r
4903 BOOLEAN saveAnimate;
\r
4904 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4905 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4906 ChessMove moveType;
\r
4909 if (message == WM_MBUTTONUP) {
\r
4910 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4911 to the middle button: we simulate pressing the left button too!
\r
4913 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4914 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4920 pt.x = LOWORD(lParam);
\r
4921 pt.y = HIWORD(lParam);
\r
4922 x = EventToSquare(pt.x - boardRect.left);
\r
4923 y = EventToSquare(pt.y - boardRect.top);
\r
4924 if (!flipView && y >= 0) {
\r
4925 y = BOARD_HEIGHT - 1 - y;
\r
4927 if (flipView && x >= 0) {
\r
4928 x = BOARD_WIDTH - 1 - x;
\r
4931 switch (message) {
\r
4932 case WM_LBUTTONDOWN:
\r
4933 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4934 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4935 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4936 if(gameInfo.holdingsWidth &&
\r
4937 (WhiteOnMove(currentMove)
\r
4938 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4939 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4940 // click in right holdings, for determining promotion piece
\r
4941 ChessSquare p = boards[currentMove][y][x];
\r
4942 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4943 if(p != EmptySquare) {
\r
4944 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4945 fromX = fromY = -1;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4953 sameAgain = FALSE;
\r
4955 /* Downclick vertically off board; check if on clock */
\r
4956 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4957 if (gameMode == EditPosition) {
\r
4958 SetWhiteToPlayEvent();
\r
4959 } else if (gameMode == IcsPlayingBlack ||
\r
4960 gameMode == MachinePlaysWhite) {
\r
4962 } else if (gameMode == EditGame) {
\r
4963 AdjustClock(flipClock, -1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditPosition) {
\r
4967 SetBlackToPlayEvent();
\r
4968 } else if (gameMode == IcsPlayingWhite ||
\r
4969 gameMode == MachinePlaysBlack) {
\r
4971 } else if (gameMode == EditGame) {
\r
4972 AdjustClock(!flipClock, -1);
\r
4975 if (!appData.highlightLastMove) {
\r
4976 ClearHighlights();
\r
4977 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4979 fromX = fromY = -1;
\r
4980 dragInfo.start.x = dragInfo.start.y = -1;
\r
4981 dragInfo.from = dragInfo.start;
\r
4983 } else if (x < 0 || y < 0
\r
4984 /* [HGM] block clicks between board and holdings */
\r
4985 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4986 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4987 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4988 /* EditPosition, empty square, or different color piece;
\r
4989 click-click move is possible */
\r
4992 } else if (fromX == x && fromY == y) {
\r
4993 /* Downclick on same square again */
\r
4994 ClearHighlights();
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4996 sameAgain = TRUE;
\r
4997 } else if (fromX != -1 &&
\r
4998 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5000 /* Downclick on different square. */
\r
5001 /* [HGM] if on holdings file, should count as new first click ! */
\r
5002 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5005 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5006 to make sure move is legal before showing promotion popup */
\r
5007 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5008 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5009 fromX = fromY = -1;
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, boards[currentMove]);
\r
5014 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5015 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5016 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5017 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5018 appData.alwaysPromoteToQueen)) {
\r
5019 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5020 if (!appData.highlightLastMove) {
\r
5021 ClearHighlights();
\r
5022 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5025 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5026 SetHighlights(fromX, fromY, toX, toY);
\r
5027 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5028 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5029 If promotion to Q is legal, all are legal! */
\r
5030 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5031 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5032 // kludge to temporarily execute move on display, without promoting yet
\r
5033 promotionChoice = TRUE;
\r
5034 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5035 boards[currentMove][toY][toX] = p;
\r
5036 DrawPosition(FALSE, boards[currentMove]);
\r
5037 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5038 boards[currentMove][toY][toX] = q;
\r
5039 DisplayMessage("Select piece from holdings", "");
\r
5041 PromotionPopup(hwnd);
\r
5043 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5044 if (appData.animate || appData.highlightLastMove) {
\r
5045 SetHighlights(fromX, fromY, toX, toY);
\r
5047 ClearHighlights();
\r
5049 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5050 if (appData.animate && !appData.highlightLastMove) {
\r
5051 ClearHighlights();
\r
5052 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5055 fromX = fromY = -1;
\r
5059 if (gotPremove && moveType != Comment) {
\r
5060 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5062 } else ClearHighlights();
\r
5063 fromX = fromY = -1;
\r
5064 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5065 if(moveType != Comment) break;
\r
5067 /* First downclick, or restart on a square with same color piece */
\r
5068 if (!frozen && OKToStartUserMove(x, y)) {
\r
5071 dragInfo.lastpos = pt;
\r
5072 dragInfo.from.x = fromX;
\r
5073 dragInfo.from.y = fromY;
\r
5074 dragInfo.start = dragInfo.from;
\r
5075 SetCapture(hwndMain);
\r
5077 fromX = fromY = -1;
\r
5078 dragInfo.start.x = dragInfo.start.y = -1;
\r
5079 dragInfo.from = dragInfo.start;
\r
5080 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5084 case WM_LBUTTONUP:
\r
5086 if (fromX == -1) break;
\r
5087 if (x == fromX && y == fromY) {
\r
5088 dragInfo.from.x = dragInfo.from.y = -1;
\r
5089 /* Upclick on same square */
\r
5091 /* Clicked same square twice: abort click-click move */
\r
5092 fromX = fromY = -1;
\r
5094 ClearPremoveHighlights();
\r
5096 /* First square clicked: start click-click move */
\r
5097 SetHighlights(fromX, fromY, -1, -1);
\r
5099 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5100 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5101 /* Errant click; ignore */
\r
5104 /* Finish drag move. */
\r
5105 if (appData.debugMode) {
\r
5106 fprintf(debugFP, "release\n");
\r
5108 dragInfo.from.x = dragInfo.from.y = -1;
\r
5111 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5112 appData.animate = appData.animate && !appData.animateDragging;
\r
5113 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5114 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5115 fromX = fromY = -1;
\r
5116 ClearHighlights();
\r
5117 DrawPosition(FALSE, boards[currentMove]);
\r
5118 appData.animate = saveAnimate;
\r
5121 if(moveType != ImpossibleMove) {
\r
5122 /* [HGM] use move type to determine if move is promotion.
\r
5123 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5124 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5125 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5126 appData.alwaysPromoteToQueen))
\r
5127 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5129 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5130 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5132 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5133 // kludge to temporarily execute move on display, wthout promotng yet
\r
5134 promotionChoice = TRUE;
\r
5135 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5136 boards[currentMove][toY][toX] = p;
\r
5137 DrawPosition(FALSE, boards[currentMove]);
\r
5138 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5139 boards[currentMove][toY][toX] = q;
\r
5140 appData.animate = saveAnimate;
\r
5141 DisplayMessage("Select piece from holdings", "");
\r
5144 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5146 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5147 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5148 moveType == WhiteCapturesEnPassant ||
\r
5149 moveType == BlackCapturesEnPassant ) )
\r
5150 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5151 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5154 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5155 appData.animate = saveAnimate;
\r
5156 fromX = fromY = -1;
\r
5157 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5158 ClearHighlights();
\r
5160 if (appData.animate || appData.animateDragging ||
\r
5161 appData.highlightDragging || gotPremove) {
\r
5162 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5165 dragInfo.start.x = dragInfo.start.y = -1;
\r
5166 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5169 case WM_MOUSEMOVE:
\r
5170 if ((appData.animateDragging || appData.highlightDragging)
\r
5171 && (wParam & MK_LBUTTON)
\r
5172 && dragInfo.from.x >= 0)
\r
5174 BOOL full_repaint = FALSE;
\r
5176 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5177 if (appData.animateDragging) {
\r
5178 dragInfo.pos = pt;
\r
5180 if (appData.highlightDragging) {
\r
5181 SetHighlights(fromX, fromY, x, y);
\r
5182 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5183 full_repaint = TRUE;
\r
5187 DrawPosition( full_repaint, NULL);
\r
5189 dragInfo.lastpos = dragInfo.pos;
\r
5193 case WM_MOUSEWHEEL: // [DM]
\r
5194 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5195 /* Mouse Wheel is being rolled forward
\r
5196 * Play moves forward
\r
5198 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5199 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5200 /* Mouse Wheel is being rolled backward
\r
5201 * Play moves backward
\r
5203 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5204 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5208 case WM_MBUTTONDOWN:
\r
5209 case WM_RBUTTONDOWN:
\r
5212 fromX = fromY = -1;
\r
5213 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5214 dragInfo.start.x = dragInfo.start.y = -1;
\r
5215 dragInfo.from = dragInfo.start;
\r
5216 dragInfo.lastpos = dragInfo.pos;
\r
5217 if (appData.highlightDragging) {
\r
5218 ClearHighlights();
\r
5221 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5222 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5223 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5224 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5225 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5228 DrawPosition(TRUE, NULL);
\r
5230 switch (gameMode) {
\r
5231 case EditPosition:
\r
5232 case IcsExamining:
\r
5233 if (x < 0 || y < 0) break;
\r
5236 if (message == WM_MBUTTONDOWN) {
\r
5237 buttonCount = 3; /* even if system didn't think so */
\r
5238 if (wParam & MK_SHIFT)
\r
5239 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5241 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5242 } else { /* message == WM_RBUTTONDOWN */
\r
5243 /* Just have one menu, on the right button. Windows users don't
\r
5244 think to try the middle one, and sometimes other software steals
\r
5245 it, or it doesn't really exist. */
\r
5246 if(gameInfo.variant != VariantShogi)
\r
5247 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5249 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5252 case IcsPlayingWhite:
\r
5253 case IcsPlayingBlack:
\r
5255 case MachinePlaysWhite:
\r
5256 case MachinePlaysBlack:
\r
5257 if (appData.testLegality &&
\r
5258 gameInfo.variant != VariantBughouse &&
\r
5259 gameInfo.variant != VariantCrazyhouse) break;
\r
5260 if (x < 0 || y < 0) break;
\r
5263 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5264 SetupDropMenu(hmenu);
\r
5265 MenuPopup(hwnd, pt, hmenu, -1);
\r
5276 /* Preprocess messages for buttons in main window */
\r
5278 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5280 int id = GetWindowLong(hwnd, GWL_ID);
\r
5283 for (i=0; i<N_BUTTONS; i++) {
\r
5284 if (buttonDesc[i].id == id) break;
\r
5286 if (i == N_BUTTONS) return 0;
\r
5287 switch (message) {
\r
5292 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5293 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5300 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5303 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5304 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5305 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5306 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5308 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5310 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5311 PopUpMoveDialog((char)wParam);
\r
5317 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5320 /* Process messages for Promotion dialog box */
\r
5322 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5326 switch (message) {
\r
5327 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5328 /* Center the dialog over the application window */
\r
5329 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5330 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5331 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5332 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5333 SW_SHOW : SW_HIDE);
\r
5334 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5335 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5336 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5337 PieceToChar(WhiteAngel) != '~') ||
\r
5338 (PieceToChar(BlackAngel) >= 'A' &&
\r
5339 PieceToChar(BlackAngel) != '~') ) ?
\r
5340 SW_SHOW : SW_HIDE);
\r
5341 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5342 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5343 PieceToChar(WhiteMarshall) != '~') ||
\r
5344 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5345 PieceToChar(BlackMarshall) != '~') ) ?
\r
5346 SW_SHOW : SW_HIDE);
\r
5347 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5348 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5349 gameInfo.variant != VariantShogi ?
\r
5350 SW_SHOW : SW_HIDE);
\r
5351 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5352 gameInfo.variant != VariantShogi ?
\r
5353 SW_SHOW : SW_HIDE);
\r
5354 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5355 gameInfo.variant == VariantShogi ?
\r
5356 SW_SHOW : SW_HIDE);
\r
5357 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5358 gameInfo.variant == VariantShogi ?
\r
5359 SW_SHOW : SW_HIDE);
\r
5360 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5361 gameInfo.variant == VariantSuper ?
\r
5362 SW_SHOW : SW_HIDE);
\r
5365 case WM_COMMAND: /* message: received a command */
\r
5366 switch (LOWORD(wParam)) {
\r
5368 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5369 ClearHighlights();
\r
5370 DrawPosition(FALSE, NULL);
\r
5373 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5376 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5379 promoChar = PieceToChar(BlackRook);
\r
5382 promoChar = PieceToChar(BlackBishop);
\r
5384 case PB_Chancellor:
\r
5385 promoChar = PieceToChar(BlackMarshall);
\r
5387 case PB_Archbishop:
\r
5388 promoChar = PieceToChar(BlackAngel);
\r
5391 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5396 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5397 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5398 only show the popup when we are already sure the move is valid or
\r
5399 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5400 will figure out it is a promotion from the promoChar. */
\r
5401 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5402 if (!appData.highlightLastMove) {
\r
5403 ClearHighlights();
\r
5404 DrawPosition(FALSE, NULL);
\r
5411 /* Pop up promotion dialog */
\r
5413 PromotionPopup(HWND hwnd)
\r
5417 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5418 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5419 hwnd, (DLGPROC)lpProc);
\r
5420 FreeProcInstance(lpProc);
\r
5423 /* Toggle ShowThinking */
\r
5425 ToggleShowThinking()
\r
5427 appData.showThinking = !appData.showThinking;
\r
5428 ShowThinkingEvent();
\r
5432 LoadGameDialog(HWND hwnd, char* title)
\r
5436 char fileTitle[MSG_SIZ];
\r
5437 f = OpenFileDialog(hwnd, "rb", "",
\r
5438 appData.oldSaveStyle ? "gam" : "pgn",
\r
5440 title, &number, fileTitle, NULL);
\r
5442 cmailMsgLoaded = FALSE;
\r
5443 if (number == 0) {
\r
5444 int error = GameListBuild(f);
\r
5446 DisplayError("Cannot build game list", error);
\r
5447 } else if (!ListEmpty(&gameList) &&
\r
5448 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5449 GameListPopUp(f, fileTitle);
\r
5452 GameListDestroy();
\r
5455 LoadGame(f, number, fileTitle, FALSE);
\r
5460 ChangedConsoleFont()
\r
5463 CHARRANGE tmpsel, sel;
\r
5464 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5465 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5466 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5469 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5470 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5471 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5472 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5473 * size. This was undocumented in the version of MSVC++ that I had
\r
5474 * when I wrote the code, but is apparently documented now.
\r
5476 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5477 cfmt.bCharSet = f->lf.lfCharSet;
\r
5478 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5479 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5480 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5481 /* Why are the following seemingly needed too? */
\r
5482 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5483 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5484 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5486 tmpsel.cpMax = -1; /*999999?*/
\r
5487 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5488 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5489 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5490 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5492 paraf.cbSize = sizeof(paraf);
\r
5493 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5494 paraf.dxStartIndent = 0;
\r
5495 paraf.dxOffset = WRAP_INDENT;
\r
5496 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5497 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5500 /*---------------------------------------------------------------------------*\
\r
5502 * Window Proc for main window
\r
5504 \*---------------------------------------------------------------------------*/
\r
5506 /* Process messages for main window, etc. */
\r
5508 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5511 int wmId, wmEvent;
\r
5515 char fileTitle[MSG_SIZ];
\r
5516 char buf[MSG_SIZ];
\r
5517 static SnapData sd;
\r
5519 switch (message) {
\r
5521 case WM_PAINT: /* message: repaint portion of window */
\r
5525 case WM_ERASEBKGND:
\r
5526 if (IsIconic(hwnd)) {
\r
5527 /* Cheat; change the message */
\r
5528 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5530 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5534 case WM_LBUTTONDOWN:
\r
5535 case WM_MBUTTONDOWN:
\r
5536 case WM_RBUTTONDOWN:
\r
5537 case WM_LBUTTONUP:
\r
5538 case WM_MBUTTONUP:
\r
5539 case WM_RBUTTONUP:
\r
5540 case WM_MOUSEMOVE:
\r
5541 case WM_MOUSEWHEEL:
\r
5542 MouseEvent(hwnd, message, wParam, lParam);
\r
5545 JAWS_KB_NAVIGATION
\r
5549 JAWS_ALT_INTERCEPT
\r
5551 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5552 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5553 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5554 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5556 SendMessage(h, message, wParam, lParam);
\r
5557 } else if(lParam != KF_REPEAT) {
\r
5558 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5559 PopUpMoveDialog((char)wParam);
\r
5560 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5561 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5566 case WM_PALETTECHANGED:
\r
5567 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5569 HDC hdc = GetDC(hwndMain);
\r
5570 SelectPalette(hdc, hPal, TRUE);
\r
5571 nnew = RealizePalette(hdc);
\r
5573 paletteChanged = TRUE;
\r
5574 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5576 ReleaseDC(hwnd, hdc);
\r
5580 case WM_QUERYNEWPALETTE:
\r
5581 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5583 HDC hdc = GetDC(hwndMain);
\r
5584 paletteChanged = FALSE;
\r
5585 SelectPalette(hdc, hPal, FALSE);
\r
5586 nnew = RealizePalette(hdc);
\r
5588 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5590 ReleaseDC(hwnd, hdc);
\r
5595 case WM_COMMAND: /* message: command from application menu */
\r
5596 wmId = LOWORD(wParam);
\r
5597 wmEvent = HIWORD(wParam);
\r
5602 AnalysisPopDown();
\r
5603 SAY("new game enter a move to play against the computer with white");
\r
5606 case IDM_NewGameFRC:
\r
5607 if( NewGameFRC() == 0 ) {
\r
5609 AnalysisPopDown();
\r
5613 case IDM_NewVariant:
\r
5614 NewVariantPopup(hwnd);
\r
5617 case IDM_LoadGame:
\r
5618 LoadGameDialog(hwnd, "Load Game from File");
\r
5621 case IDM_LoadNextGame:
\r
5625 case IDM_LoadPrevGame:
\r
5629 case IDM_ReloadGame:
\r
5633 case IDM_LoadPosition:
\r
5634 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5635 Reset(FALSE, TRUE);
\r
5638 f = OpenFileDialog(hwnd, "rb", "",
\r
5639 appData.oldSaveStyle ? "pos" : "fen",
\r
5641 "Load Position from File", &number, fileTitle, NULL);
\r
5643 LoadPosition(f, number, fileTitle);
\r
5647 case IDM_LoadNextPosition:
\r
5648 ReloadPosition(1);
\r
5651 case IDM_LoadPrevPosition:
\r
5652 ReloadPosition(-1);
\r
5655 case IDM_ReloadPosition:
\r
5656 ReloadPosition(0);
\r
5659 case IDM_SaveGame:
\r
5660 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5661 f = OpenFileDialog(hwnd, "a", defName,
\r
5662 appData.oldSaveStyle ? "gam" : "pgn",
\r
5664 "Save Game to File", NULL, fileTitle, NULL);
\r
5666 SaveGame(f, 0, "");
\r
5670 case IDM_SavePosition:
\r
5671 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5672 f = OpenFileDialog(hwnd, "a", defName,
\r
5673 appData.oldSaveStyle ? "pos" : "fen",
\r
5675 "Save Position to File", NULL, fileTitle, NULL);
\r
5677 SavePosition(f, 0, "");
\r
5681 case IDM_SaveDiagram:
\r
5682 defName = "diagram";
\r
5683 f = OpenFileDialog(hwnd, "wb", defName,
\r
5686 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5692 case IDM_CopyGame:
\r
5693 CopyGameToClipboard();
\r
5696 case IDM_PasteGame:
\r
5697 PasteGameFromClipboard();
\r
5700 case IDM_CopyGameListToClipboard:
\r
5701 CopyGameListToClipboard();
\r
5704 /* [AS] Autodetect FEN or PGN data */
\r
5705 case IDM_PasteAny:
\r
5706 PasteGameOrFENFromClipboard();
\r
5709 /* [AS] Move history */
\r
5710 case IDM_ShowMoveHistory:
\r
5711 if( MoveHistoryIsUp() ) {
\r
5712 MoveHistoryPopDown();
\r
5715 MoveHistoryPopUp();
\r
5719 /* [AS] Eval graph */
\r
5720 case IDM_ShowEvalGraph:
\r
5721 if( EvalGraphIsUp() ) {
\r
5722 EvalGraphPopDown();
\r
5726 SetFocus(hwndMain);
\r
5730 /* [AS] Engine output */
\r
5731 case IDM_ShowEngineOutput:
\r
5732 if( EngineOutputIsUp() ) {
\r
5733 EngineOutputPopDown();
\r
5736 EngineOutputPopUp();
\r
5740 /* [AS] User adjudication */
\r
5741 case IDM_UserAdjudication_White:
\r
5742 UserAdjudicationEvent( +1 );
\r
5745 case IDM_UserAdjudication_Black:
\r
5746 UserAdjudicationEvent( -1 );
\r
5749 case IDM_UserAdjudication_Draw:
\r
5750 UserAdjudicationEvent( 0 );
\r
5753 /* [AS] Game list options dialog */
\r
5754 case IDM_GameListOptions:
\r
5755 GameListOptions();
\r
5762 case IDM_CopyPosition:
\r
5763 CopyFENToClipboard();
\r
5766 case IDM_PastePosition:
\r
5767 PasteFENFromClipboard();
\r
5770 case IDM_MailMove:
\r
5774 case IDM_ReloadCMailMsg:
\r
5775 Reset(TRUE, TRUE);
\r
5776 ReloadCmailMsgEvent(FALSE);
\r
5779 case IDM_Minimize:
\r
5780 ShowWindow(hwnd, SW_MINIMIZE);
\r
5787 case IDM_MachineWhite:
\r
5788 MachineWhiteEvent();
\r
5790 * refresh the tags dialog only if it's visible
\r
5792 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5794 tags = PGNTags(&gameInfo);
\r
5795 TagsPopUp(tags, CmailMsg());
\r
5798 SAY("computer starts playing white");
\r
5801 case IDM_MachineBlack:
\r
5802 MachineBlackEvent();
\r
5804 * refresh the tags dialog only if it's visible
\r
5806 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5808 tags = PGNTags(&gameInfo);
\r
5809 TagsPopUp(tags, CmailMsg());
\r
5812 SAY("computer starts playing black");
\r
5815 case IDM_TwoMachines:
\r
5816 TwoMachinesEvent();
\r
5818 * refresh the tags dialog only if it's visible
\r
5820 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5822 tags = PGNTags(&gameInfo);
\r
5823 TagsPopUp(tags, CmailMsg());
\r
5826 SAY("programs start playing each other");
\r
5829 case IDM_AnalysisMode:
\r
5830 if (!first.analysisSupport) {
\r
5831 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5832 DisplayError(buf, 0);
\r
5834 SAY("analyzing current position");
\r
5835 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5836 if (appData.icsActive) {
\r
5837 if (gameMode != IcsObserving) {
\r
5838 sprintf(buf, "You are not observing a game");
\r
5839 DisplayError(buf, 0);
\r
5840 /* secure check */
\r
5841 if (appData.icsEngineAnalyze) {
\r
5842 if (appData.debugMode)
\r
5843 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5844 ExitAnalyzeMode();
\r
5850 /* if enable, user want disable icsEngineAnalyze */
\r
5851 if (appData.icsEngineAnalyze) {
\r
5852 ExitAnalyzeMode();
\r
5856 appData.icsEngineAnalyze = TRUE;
\r
5857 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5860 if (!appData.showThinking) ToggleShowThinking();
\r
5861 AnalyzeModeEvent();
\r
5865 case IDM_AnalyzeFile:
\r
5866 if (!first.analysisSupport) {
\r
5867 char buf[MSG_SIZ];
\r
5868 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5869 DisplayError(buf, 0);
\r
5871 if (!appData.showThinking) ToggleShowThinking();
\r
5872 AnalyzeFileEvent();
\r
5873 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5874 AnalysisPeriodicEvent(1);
\r
5878 case IDM_IcsClient:
\r
5882 case IDM_EditGame:
\r
5887 case IDM_EditPosition:
\r
5888 EditPositionEvent();
\r
5889 SAY("to set up a position type a FEN");
\r
5892 case IDM_Training:
\r
5896 case IDM_ShowGameList:
\r
5897 ShowGameListProc();
\r
5900 case IDM_EditTags:
\r
5904 case IDM_EditComment:
\r
5905 if (commentDialogUp && editComment) {
\r
5908 EditCommentEvent();
\r
5928 case IDM_CallFlag:
\r
5948 case IDM_StopObserving:
\r
5949 StopObservingEvent();
\r
5952 case IDM_StopExamining:
\r
5953 StopExaminingEvent();
\r
5956 case IDM_TypeInMove:
\r
5957 PopUpMoveDialog('\000');
\r
5960 case IDM_TypeInName:
\r
5961 PopUpNameDialog('\000');
\r
5964 case IDM_Backward:
\r
5966 SetFocus(hwndMain);
\r
5973 SetFocus(hwndMain);
\r
5978 SetFocus(hwndMain);
\r
5983 SetFocus(hwndMain);
\r
5990 case IDM_TruncateGame:
\r
5991 TruncateGameEvent();
\r
5998 case IDM_RetractMove:
\r
5999 RetractMoveEvent();
\r
6002 case IDM_FlipView:
\r
6003 flipView = !flipView;
\r
6004 DrawPosition(FALSE, NULL);
\r
6007 case IDM_FlipClock:
\r
6008 flipClock = !flipClock;
\r
6009 DisplayBothClocks();
\r
6010 DrawPosition(FALSE, NULL);
\r
6013 case IDM_MuteSounds:
\r
6014 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6015 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6016 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6019 case IDM_GeneralOptions:
\r
6020 GeneralOptionsPopup(hwnd);
\r
6021 DrawPosition(TRUE, NULL);
\r
6024 case IDM_BoardOptions:
\r
6025 BoardOptionsPopup(hwnd);
\r
6028 case IDM_EnginePlayOptions:
\r
6029 EnginePlayOptionsPopup(hwnd);
\r
6032 case IDM_Engine1Options:
\r
6033 EngineOptionsPopup(hwnd, &first);
\r
6036 case IDM_Engine2Options:
\r
6037 EngineOptionsPopup(hwnd, &second);
\r
6040 case IDM_OptionsUCI:
\r
6041 UciOptionsPopup(hwnd);
\r
6044 case IDM_IcsOptions:
\r
6045 IcsOptionsPopup(hwnd);
\r
6049 FontsOptionsPopup(hwnd);
\r
6053 SoundOptionsPopup(hwnd);
\r
6056 case IDM_CommPort:
\r
6057 CommPortOptionsPopup(hwnd);
\r
6060 case IDM_LoadOptions:
\r
6061 LoadOptionsPopup(hwnd);
\r
6064 case IDM_SaveOptions:
\r
6065 SaveOptionsPopup(hwnd);
\r
6068 case IDM_TimeControl:
\r
6069 TimeControlOptionsPopup(hwnd);
\r
6072 case IDM_SaveSettings:
\r
6073 SaveSettings(settingsFileName);
\r
6076 case IDM_SaveSettingsOnExit:
\r
6077 saveSettingsOnExit = !saveSettingsOnExit;
\r
6078 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6079 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6080 MF_CHECKED : MF_UNCHECKED));
\r
6091 case IDM_AboutGame:
\r
6096 appData.debugMode = !appData.debugMode;
\r
6097 if (appData.debugMode) {
\r
6098 char dir[MSG_SIZ];
\r
6099 GetCurrentDirectory(MSG_SIZ, dir);
\r
6100 SetCurrentDirectory(installDir);
\r
6101 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6102 SetCurrentDirectory(dir);
\r
6103 setbuf(debugFP, NULL);
\r
6110 case IDM_HELPCONTENTS:
\r
6111 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6112 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6113 MessageBox (GetFocus(),
\r
6114 "Unable to activate help",
\r
6115 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6119 case IDM_HELPSEARCH:
\r
6120 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6121 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6122 MessageBox (GetFocus(),
\r
6123 "Unable to activate help",
\r
6124 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6128 case IDM_HELPHELP:
\r
6129 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6130 MessageBox (GetFocus(),
\r
6131 "Unable to activate help",
\r
6132 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6137 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6139 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6140 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6141 FreeProcInstance(lpProc);
\r
6144 case IDM_DirectCommand1:
\r
6145 AskQuestionEvent("Direct Command",
\r
6146 "Send to chess program:", "", "1");
\r
6148 case IDM_DirectCommand2:
\r
6149 AskQuestionEvent("Direct Command",
\r
6150 "Send to second chess program:", "", "2");
\r
6153 case EP_WhitePawn:
\r
6154 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6155 fromX = fromY = -1;
\r
6158 case EP_WhiteKnight:
\r
6159 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6160 fromX = fromY = -1;
\r
6163 case EP_WhiteBishop:
\r
6164 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6165 fromX = fromY = -1;
\r
6168 case EP_WhiteRook:
\r
6169 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6170 fromX = fromY = -1;
\r
6173 case EP_WhiteQueen:
\r
6174 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6175 fromX = fromY = -1;
\r
6178 case EP_WhiteFerz:
\r
6179 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6180 fromX = fromY = -1;
\r
6183 case EP_WhiteWazir:
\r
6184 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6185 fromX = fromY = -1;
\r
6188 case EP_WhiteAlfil:
\r
6189 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6190 fromX = fromY = -1;
\r
6193 case EP_WhiteCannon:
\r
6194 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6195 fromX = fromY = -1;
\r
6198 case EP_WhiteCardinal:
\r
6199 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6200 fromX = fromY = -1;
\r
6203 case EP_WhiteMarshall:
\r
6204 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6205 fromX = fromY = -1;
\r
6208 case EP_WhiteKing:
\r
6209 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6210 fromX = fromY = -1;
\r
6213 case EP_BlackPawn:
\r
6214 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6215 fromX = fromY = -1;
\r
6218 case EP_BlackKnight:
\r
6219 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6220 fromX = fromY = -1;
\r
6223 case EP_BlackBishop:
\r
6224 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6225 fromX = fromY = -1;
\r
6228 case EP_BlackRook:
\r
6229 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6230 fromX = fromY = -1;
\r
6233 case EP_BlackQueen:
\r
6234 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6235 fromX = fromY = -1;
\r
6238 case EP_BlackFerz:
\r
6239 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6240 fromX = fromY = -1;
\r
6243 case EP_BlackWazir:
\r
6244 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6245 fromX = fromY = -1;
\r
6248 case EP_BlackAlfil:
\r
6249 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_BlackCannon:
\r
6254 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_BlackCardinal:
\r
6259 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_BlackMarshall:
\r
6264 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_BlackKing:
\r
6269 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_EmptySquare:
\r
6274 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_ClearBoard:
\r
6279 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6284 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6289 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6294 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6299 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6304 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6309 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6314 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6319 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6324 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6329 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6335 case CLOCK_TIMER_ID:
\r
6336 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6337 clockTimerEvent = 0;
\r
6338 DecrementClocks(); /* call into back end */
\r
6340 case LOAD_GAME_TIMER_ID:
\r
6341 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6342 loadGameTimerEvent = 0;
\r
6343 AutoPlayGameLoop(); /* call into back end */
\r
6345 case ANALYSIS_TIMER_ID:
\r
6346 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6347 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6348 AnalysisPeriodicEvent(0);
\r
6350 KillTimer(hwnd, analysisTimerEvent);
\r
6351 analysisTimerEvent = 0;
\r
6354 case DELAYED_TIMER_ID:
\r
6355 KillTimer(hwnd, delayedTimerEvent);
\r
6356 delayedTimerEvent = 0;
\r
6357 delayedTimerCallback();
\r
6362 case WM_USER_Input:
\r
6363 InputEvent(hwnd, message, wParam, lParam);
\r
6366 /* [AS] Also move "attached" child windows */
\r
6367 case WM_WINDOWPOSCHANGING:
\r
6369 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6370 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6372 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6373 /* Window is moving */
\r
6376 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6377 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6378 rcMain.right = boardX + winWidth;
\r
6379 rcMain.top = boardY;
\r
6380 rcMain.bottom = boardY + winHeight;
\r
6382 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6383 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6384 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6385 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6386 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6393 /* [AS] Snapping */
\r
6394 case WM_ENTERSIZEMOVE:
\r
6395 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6396 if (hwnd == hwndMain) {
\r
6397 doingSizing = TRUE;
\r
6400 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6404 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6405 if (hwnd == hwndMain) {
\r
6406 lastSizing = wParam;
\r
6411 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6412 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6414 case WM_EXITSIZEMOVE:
\r
6415 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6416 if (hwnd == hwndMain) {
\r
6418 doingSizing = FALSE;
\r
6419 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6420 GetClientRect(hwnd, &client);
\r
6421 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6423 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6425 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6428 case WM_DESTROY: /* message: window being destroyed */
\r
6429 PostQuitMessage(0);
\r
6433 if (hwnd == hwndMain) {
\r
6438 default: /* Passes it on if unprocessed */
\r
6439 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6444 /*---------------------------------------------------------------------------*\
\r
6446 * Misc utility routines
\r
6448 \*---------------------------------------------------------------------------*/
\r
6451 * Decent random number generator, at least not as bad as Windows
\r
6452 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6454 unsigned int randstate;
\r
6459 randstate = randstate * 1664525 + 1013904223;
\r
6460 return (int) randstate & 0x7fffffff;
\r
6464 mysrandom(unsigned int seed)
\r
6471 * returns TRUE if user selects a different color, FALSE otherwise
\r
6475 ChangeColor(HWND hwnd, COLORREF *which)
\r
6477 static BOOL firstTime = TRUE;
\r
6478 static DWORD customColors[16];
\r
6480 COLORREF newcolor;
\r
6485 /* Make initial colors in use available as custom colors */
\r
6486 /* Should we put the compiled-in defaults here instead? */
\r
6488 customColors[i++] = lightSquareColor & 0xffffff;
\r
6489 customColors[i++] = darkSquareColor & 0xffffff;
\r
6490 customColors[i++] = whitePieceColor & 0xffffff;
\r
6491 customColors[i++] = blackPieceColor & 0xffffff;
\r
6492 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6493 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6495 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6496 customColors[i++] = textAttribs[ccl].color;
\r
6498 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6499 firstTime = FALSE;
\r
6502 cc.lStructSize = sizeof(cc);
\r
6503 cc.hwndOwner = hwnd;
\r
6504 cc.hInstance = NULL;
\r
6505 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6506 cc.lpCustColors = (LPDWORD) customColors;
\r
6507 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6509 if (!ChooseColor(&cc)) return FALSE;
\r
6511 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6512 if (newcolor == *which) return FALSE;
\r
6513 *which = newcolor;
\r
6517 InitDrawingColors();
\r
6518 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6523 MyLoadSound(MySound *ms)
\r
6529 if (ms->data) free(ms->data);
\r
6532 switch (ms->name[0]) {
\r
6538 /* System sound from Control Panel. Don't preload here. */
\r
6542 if (ms->name[1] == NULLCHAR) {
\r
6543 /* "!" alone = silence */
\r
6546 /* Builtin wave resource. Error if not found. */
\r
6547 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6548 if (h == NULL) break;
\r
6549 ms->data = (void *)LoadResource(hInst, h);
\r
6550 if (h == NULL) break;
\r
6555 /* .wav file. Error if not found. */
\r
6556 f = fopen(ms->name, "rb");
\r
6557 if (f == NULL) break;
\r
6558 if (fstat(fileno(f), &st) < 0) break;
\r
6559 ms->data = malloc(st.st_size);
\r
6560 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6566 char buf[MSG_SIZ];
\r
6567 sprintf(buf, "Error loading sound %s", ms->name);
\r
6568 DisplayError(buf, GetLastError());
\r
6574 MyPlaySound(MySound *ms)
\r
6576 BOOLEAN ok = FALSE;
\r
6578 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6579 switch (ms->name[0]) {
\r
6581 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6586 /* System sound from Control Panel (deprecated feature).
\r
6587 "$" alone or an unset sound name gets default beep (still in use). */
\r
6588 if (ms->name[1]) {
\r
6589 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6591 if (!ok) ok = MessageBeep(MB_OK);
\r
6594 /* Builtin wave resource, or "!" alone for silence */
\r
6595 if (ms->name[1]) {
\r
6596 if (ms->data == NULL) return FALSE;
\r
6597 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6603 /* .wav file. Error if not found. */
\r
6604 if (ms->data == NULL) return FALSE;
\r
6605 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6608 /* Don't print an error: this can happen innocently if the sound driver
\r
6609 is busy; for instance, if another instance of WinBoard is playing
\r
6610 a sound at about the same time. */
\r
6616 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6619 OPENFILENAME *ofn;
\r
6620 static UINT *number; /* gross that this is static */
\r
6622 switch (message) {
\r
6623 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6624 /* Center the dialog over the application window */
\r
6625 ofn = (OPENFILENAME *) lParam;
\r
6626 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6627 number = (UINT *) ofn->lCustData;
\r
6628 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6632 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6633 return FALSE; /* Allow for further processing */
\r
6636 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6637 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6639 return FALSE; /* Allow for further processing */
\r
6645 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6647 static UINT *number;
\r
6648 OPENFILENAME *ofname;
\r
6651 case WM_INITDIALOG:
\r
6652 ofname = (OPENFILENAME *)lParam;
\r
6653 number = (UINT *)(ofname->lCustData);
\r
6656 ofnot = (OFNOTIFY *)lParam;
\r
6657 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6658 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6667 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6668 char *nameFilt, char *dlgTitle, UINT *number,
\r
6669 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6671 OPENFILENAME openFileName;
\r
6672 char buf1[MSG_SIZ];
\r
6675 if (fileName == NULL) fileName = buf1;
\r
6676 if (defName == NULL) {
\r
6677 strcpy(fileName, "*.");
\r
6678 strcat(fileName, defExt);
\r
6680 strcpy(fileName, defName);
\r
6682 if (fileTitle) strcpy(fileTitle, "");
\r
6683 if (number) *number = 0;
\r
6685 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6686 openFileName.hwndOwner = hwnd;
\r
6687 openFileName.hInstance = (HANDLE) hInst;
\r
6688 openFileName.lpstrFilter = nameFilt;
\r
6689 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6690 openFileName.nMaxCustFilter = 0L;
\r
6691 openFileName.nFilterIndex = 1L;
\r
6692 openFileName.lpstrFile = fileName;
\r
6693 openFileName.nMaxFile = MSG_SIZ;
\r
6694 openFileName.lpstrFileTitle = fileTitle;
\r
6695 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6696 openFileName.lpstrInitialDir = NULL;
\r
6697 openFileName.lpstrTitle = dlgTitle;
\r
6698 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6699 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6700 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6701 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6702 openFileName.nFileOffset = 0;
\r
6703 openFileName.nFileExtension = 0;
\r
6704 openFileName.lpstrDefExt = defExt;
\r
6705 openFileName.lCustData = (LONG) number;
\r
6706 openFileName.lpfnHook = oldDialog ?
\r
6707 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6708 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6710 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6711 GetOpenFileName(&openFileName)) {
\r
6712 /* open the file */
\r
6713 f = fopen(openFileName.lpstrFile, write);
\r
6715 MessageBox(hwnd, "File open failed", NULL,
\r
6716 MB_OK|MB_ICONEXCLAMATION);
\r
6720 int err = CommDlgExtendedError();
\r
6721 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6730 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6732 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6735 * Get the first pop-up menu in the menu template. This is the
\r
6736 * menu that TrackPopupMenu displays.
\r
6738 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6740 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6743 * TrackPopup uses screen coordinates, so convert the
\r
6744 * coordinates of the mouse click to screen coordinates.
\r
6746 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6748 /* Draw and track the floating pop-up menu. */
\r
6749 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6750 pt.x, pt.y, 0, hwnd, NULL);
\r
6752 /* Destroy the menu.*/
\r
6753 DestroyMenu(hmenu);
\r
6758 int sizeX, sizeY, newSizeX, newSizeY;
\r
6760 } ResizeEditPlusButtonsClosure;
\r
6763 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6765 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6769 if (hChild == cl->hText) return TRUE;
\r
6770 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6771 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6772 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6773 ScreenToClient(cl->hDlg, &pt);
\r
6774 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6775 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6779 /* Resize a dialog that has a (rich) edit field filling most of
\r
6780 the top, with a row of buttons below */
\r
6782 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6785 int newTextHeight, newTextWidth;
\r
6786 ResizeEditPlusButtonsClosure cl;
\r
6788 /*if (IsIconic(hDlg)) return;*/
\r
6789 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6791 cl.hdwp = BeginDeferWindowPos(8);
\r
6793 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6794 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6795 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6796 if (newTextHeight < 0) {
\r
6797 newSizeY += -newTextHeight;
\r
6798 newTextHeight = 0;
\r
6800 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6801 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6807 cl.newSizeX = newSizeX;
\r
6808 cl.newSizeY = newSizeY;
\r
6809 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6811 EndDeferWindowPos(cl.hdwp);
\r
6814 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6816 RECT rChild, rParent;
\r
6817 int wChild, hChild, wParent, hParent;
\r
6818 int wScreen, hScreen, xNew, yNew;
\r
6821 /* Get the Height and Width of the child window */
\r
6822 GetWindowRect (hwndChild, &rChild);
\r
6823 wChild = rChild.right - rChild.left;
\r
6824 hChild = rChild.bottom - rChild.top;
\r
6826 /* Get the Height and Width of the parent window */
\r
6827 GetWindowRect (hwndParent, &rParent);
\r
6828 wParent = rParent.right - rParent.left;
\r
6829 hParent = rParent.bottom - rParent.top;
\r
6831 /* Get the display limits */
\r
6832 hdc = GetDC (hwndChild);
\r
6833 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6834 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6835 ReleaseDC(hwndChild, hdc);
\r
6837 /* Calculate new X position, then adjust for screen */
\r
6838 xNew = rParent.left + ((wParent - wChild) /2);
\r
6841 } else if ((xNew+wChild) > wScreen) {
\r
6842 xNew = wScreen - wChild;
\r
6845 /* Calculate new Y position, then adjust for screen */
\r
6847 yNew = rParent.top + ((hParent - hChild) /2);
\r
6850 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6855 } else if ((yNew+hChild) > hScreen) {
\r
6856 yNew = hScreen - hChild;
\r
6859 /* Set it, and return */
\r
6860 return SetWindowPos (hwndChild, NULL,
\r
6861 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6864 /* Center one window over another */
\r
6865 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6867 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6870 /*---------------------------------------------------------------------------*\
\r
6872 * Startup Dialog functions
\r
6874 \*---------------------------------------------------------------------------*/
\r
6876 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6878 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6880 while (*cd != NULL) {
\r
6881 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6887 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6889 char buf1[ARG_MAX];
\r
6892 if (str[0] == '@') {
\r
6893 FILE* f = fopen(str + 1, "r");
\r
6895 DisplayFatalError(str + 1, errno, 2);
\r
6898 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6900 buf1[len] = NULLCHAR;
\r
6904 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6907 char buf[MSG_SIZ];
\r
6908 char *end = strchr(str, '\n');
\r
6909 if (end == NULL) return;
\r
6910 memcpy(buf, str, end - str);
\r
6911 buf[end - str] = NULLCHAR;
\r
6912 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6918 SetStartupDialogEnables(HWND hDlg)
\r
6920 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6921 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6922 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6923 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6924 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6925 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6926 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6927 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6928 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6929 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6930 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6931 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6932 IsDlgButtonChecked(hDlg, OPT_View));
\r
6936 QuoteForFilename(char *filename)
\r
6938 int dquote, space;
\r
6939 dquote = strchr(filename, '"') != NULL;
\r
6940 space = strchr(filename, ' ') != NULL;
\r
6941 if (dquote || space) {
\r
6953 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6955 char buf[MSG_SIZ];
\r
6958 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6959 q = QuoteForFilename(nthcp);
\r
6960 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6961 if (*nthdir != NULLCHAR) {
\r
6962 q = QuoteForFilename(nthdir);
\r
6963 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6965 if (*nthcp == NULLCHAR) {
\r
6966 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6967 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6968 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6969 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6974 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6976 char buf[MSG_SIZ];
\r
6980 switch (message) {
\r
6981 case WM_INITDIALOG:
\r
6982 /* Center the dialog */
\r
6983 CenterWindow (hDlg, GetDesktopWindow());
\r
6984 /* Initialize the dialog items */
\r
6985 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6986 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6987 firstChessProgramNames);
\r
6988 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6989 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6990 secondChessProgramNames);
\r
6991 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6992 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6993 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6994 if (*appData.icsHelper != NULLCHAR) {
\r
6995 char *q = QuoteForFilename(appData.icsHelper);
\r
6996 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6998 if (*appData.icsHost == NULLCHAR) {
\r
6999 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7000 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7001 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7002 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7003 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7006 if (appData.icsActive) {
\r
7007 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7009 else if (appData.noChessProgram) {
\r
7010 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7013 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7016 SetStartupDialogEnables(hDlg);
\r
7020 switch (LOWORD(wParam)) {
\r
7022 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7023 strcpy(buf, "/fcp=");
\r
7024 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7026 ParseArgs(StringGet, &p);
\r
7027 strcpy(buf, "/scp=");
\r
7028 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7030 ParseArgs(StringGet, &p);
\r
7031 appData.noChessProgram = FALSE;
\r
7032 appData.icsActive = FALSE;
\r
7033 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7034 strcpy(buf, "/ics /icshost=");
\r
7035 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7037 ParseArgs(StringGet, &p);
\r
7038 if (appData.zippyPlay) {
\r
7039 strcpy(buf, "/fcp=");
\r
7040 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7042 ParseArgs(StringGet, &p);
\r
7044 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7045 appData.noChessProgram = TRUE;
\r
7046 appData.icsActive = FALSE;
\r
7048 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7049 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7052 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7053 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7055 ParseArgs(StringGet, &p);
\r
7057 EndDialog(hDlg, TRUE);
\r
7064 case IDM_HELPCONTENTS:
\r
7065 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7066 MessageBox (GetFocus(),
\r
7067 "Unable to activate help",
\r
7068 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7073 SetStartupDialogEnables(hDlg);
\r
7081 /*---------------------------------------------------------------------------*\
\r
7083 * About box dialog functions
\r
7085 \*---------------------------------------------------------------------------*/
\r
7087 /* Process messages for "About" dialog box */
\r
7089 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7091 switch (message) {
\r
7092 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7093 /* Center the dialog over the application window */
\r
7094 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7095 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7099 case WM_COMMAND: /* message: received a command */
\r
7100 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7101 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7102 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7110 /*---------------------------------------------------------------------------*\
\r
7112 * Comment Dialog functions
\r
7114 \*---------------------------------------------------------------------------*/
\r
7117 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7119 static HANDLE hwndText = NULL;
\r
7120 int len, newSizeX, newSizeY, flags;
\r
7121 static int sizeX, sizeY;
\r
7126 switch (message) {
\r
7127 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7128 /* Initialize the dialog items */
\r
7129 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7130 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7131 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7132 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7133 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7134 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7135 SetWindowText(hDlg, commentTitle);
\r
7136 if (editComment) {
\r
7137 SetFocus(hwndText);
\r
7139 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7141 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7142 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7143 MAKELPARAM(FALSE, 0));
\r
7144 /* Size and position the dialog */
\r
7145 if (!commentDialog) {
\r
7146 commentDialog = hDlg;
\r
7147 flags = SWP_NOZORDER;
\r
7148 GetClientRect(hDlg, &rect);
\r
7149 sizeX = rect.right;
\r
7150 sizeY = rect.bottom;
\r
7151 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7152 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7153 WINDOWPLACEMENT wp;
\r
7154 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7155 wp.length = sizeof(WINDOWPLACEMENT);
\r
7157 wp.showCmd = SW_SHOW;
\r
7158 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7159 wp.rcNormalPosition.left = commentX;
\r
7160 wp.rcNormalPosition.right = commentX + commentW;
\r
7161 wp.rcNormalPosition.top = commentY;
\r
7162 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7163 SetWindowPlacement(hDlg, &wp);
\r
7165 GetClientRect(hDlg, &rect);
\r
7166 newSizeX = rect.right;
\r
7167 newSizeY = rect.bottom;
\r
7168 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7169 newSizeX, newSizeY);
\r
7176 case WM_COMMAND: /* message: received a command */
\r
7177 switch (LOWORD(wParam)) {
\r
7179 if (editComment) {
\r
7181 /* Read changed options from the dialog box */
\r
7182 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7183 len = GetWindowTextLength(hwndText);
\r
7184 str = (char *) malloc(len + 1);
\r
7185 GetWindowText(hwndText, str, len + 1);
\r
7194 ReplaceComment(commentIndex, str);
\r
7201 case OPT_CancelComment:
\r
7205 case OPT_ClearComment:
\r
7206 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7209 case OPT_EditComment:
\r
7210 EditCommentEvent();
\r
7219 newSizeX = LOWORD(lParam);
\r
7220 newSizeY = HIWORD(lParam);
\r
7221 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7226 case WM_GETMINMAXINFO:
\r
7227 /* Prevent resizing window too small */
\r
7228 mmi = (MINMAXINFO *) lParam;
\r
7229 mmi->ptMinTrackSize.x = 100;
\r
7230 mmi->ptMinTrackSize.y = 100;
\r
7237 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7242 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7244 if (str == NULL) str = "";
\r
7245 p = (char *) malloc(2 * strlen(str) + 2);
\r
7248 if (*str == '\n') *q++ = '\r';
\r
7252 if (commentText != NULL) free(commentText);
\r
7254 commentIndex = index;
\r
7255 commentTitle = title;
\r
7257 editComment = edit;
\r
7259 if (commentDialog) {
\r
7260 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7261 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7263 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7264 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7265 hwndMain, (DLGPROC)lpProc);
\r
7266 FreeProcInstance(lpProc);
\r
7268 commentDialogUp = TRUE;
\r
7272 /*---------------------------------------------------------------------------*\
\r
7274 * Type-in move dialog functions
\r
7276 \*---------------------------------------------------------------------------*/
\r
7279 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7281 char move[MSG_SIZ];
\r
7283 ChessMove moveType;
\r
7284 int fromX, fromY, toX, toY;
\r
7287 switch (message) {
\r
7288 case WM_INITDIALOG:
\r
7289 move[0] = (char) lParam;
\r
7290 move[1] = NULLCHAR;
\r
7291 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7292 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7293 SetWindowText(hInput, move);
\r
7295 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7299 switch (LOWORD(wParam)) {
\r
7301 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7302 { int n; Board board;
\r
7304 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7305 EditPositionPasteFEN(move);
\r
7306 EndDialog(hDlg, TRUE);
\r
7309 // [HGM] movenum: allow move number to be typed in any mode
\r
7310 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7311 currentMove = 2*n-1;
\r
7312 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7313 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7314 EndDialog(hDlg, TRUE);
\r
7315 DrawPosition(TRUE, boards[currentMove]);
\r
7316 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7317 else DisplayMessage("", "");
\r
7321 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7322 gameMode != Training) {
\r
7323 DisplayMoveError("Displayed move is not current");
\r
7325 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7326 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7327 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7328 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7329 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7330 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7331 if (gameMode != Training)
\r
7332 forwardMostMove = currentMove;
\r
7333 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7335 DisplayMoveError("Could not parse move");
\r
7338 EndDialog(hDlg, TRUE);
\r
7341 EndDialog(hDlg, FALSE);
\r
7352 PopUpMoveDialog(char firstchar)
\r
7356 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7357 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7358 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7359 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7360 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7361 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7362 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7363 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7364 gameMode == Training) {
\r
7365 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7366 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7367 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7368 FreeProcInstance(lpProc);
\r
7372 /*---------------------------------------------------------------------------*\
\r
7374 * Type-in name dialog functions
\r
7376 \*---------------------------------------------------------------------------*/
\r
7379 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7381 char move[MSG_SIZ];
\r
7384 switch (message) {
\r
7385 case WM_INITDIALOG:
\r
7386 move[0] = (char) lParam;
\r
7387 move[1] = NULLCHAR;
\r
7388 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7389 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7390 SetWindowText(hInput, move);
\r
7392 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7396 switch (LOWORD(wParam)) {
\r
7398 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7399 appData.userName = strdup(move);
\r
7402 EndDialog(hDlg, TRUE);
\r
7405 EndDialog(hDlg, FALSE);
\r
7416 PopUpNameDialog(char firstchar)
\r
7420 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7421 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7422 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7423 FreeProcInstance(lpProc);
\r
7426 /*---------------------------------------------------------------------------*\
\r
7430 \*---------------------------------------------------------------------------*/
\r
7432 /* Nonmodal error box */
\r
7433 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7434 WPARAM wParam, LPARAM lParam);
\r
7437 ErrorPopUp(char *title, char *content)
\r
7441 BOOLEAN modal = hwndMain == NULL;
\r
7459 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7460 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7463 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7465 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7466 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7467 hwndMain, (DLGPROC)lpProc);
\r
7468 FreeProcInstance(lpProc);
\r
7475 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7476 if (errorDialog == NULL) return;
\r
7477 DestroyWindow(errorDialog);
\r
7478 errorDialog = NULL;
\r
7482 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7487 switch (message) {
\r
7488 case WM_INITDIALOG:
\r
7489 GetWindowRect(hDlg, &rChild);
\r
7492 SetWindowPos(hDlg, NULL, rChild.left,
\r
7493 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7494 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7498 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7499 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7500 and it doesn't work when you resize the dialog.
\r
7501 For now, just give it a default position.
\r
7503 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7505 errorDialog = hDlg;
\r
7506 SetWindowText(hDlg, errorTitle);
\r
7507 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7508 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7512 switch (LOWORD(wParam)) {
\r
7515 if (errorDialog == hDlg) errorDialog = NULL;
\r
7516 DestroyWindow(hDlg);
\r
7528 HWND gothicDialog = NULL;
\r
7531 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7535 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7537 switch (message) {
\r
7538 case WM_INITDIALOG:
\r
7539 GetWindowRect(hDlg, &rChild);
\r
7541 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7545 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7546 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7547 and it doesn't work when you resize the dialog.
\r
7548 For now, just give it a default position.
\r
7550 gothicDialog = hDlg;
\r
7551 SetWindowText(hDlg, errorTitle);
\r
7552 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7553 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7557 switch (LOWORD(wParam)) {
\r
7560 if (errorDialog == hDlg) errorDialog = NULL;
\r
7561 DestroyWindow(hDlg);
\r
7573 GothicPopUp(char *title, VariantClass variant)
\r
7576 static char *lastTitle;
\r
7578 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7579 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7581 if(lastTitle != title && gothicDialog != NULL) {
\r
7582 DestroyWindow(gothicDialog);
\r
7583 gothicDialog = NULL;
\r
7585 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7586 title = lastTitle;
\r
7587 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7588 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7589 hwndMain, (DLGPROC)lpProc);
\r
7590 FreeProcInstance(lpProc);
\r
7595 /*---------------------------------------------------------------------------*\
\r
7597 * Ics Interaction console functions
\r
7599 \*---------------------------------------------------------------------------*/
\r
7601 #define HISTORY_SIZE 64
\r
7602 static char *history[HISTORY_SIZE];
\r
7603 int histIn = 0, histP = 0;
\r
7606 SaveInHistory(char *cmd)
\r
7608 if (history[histIn] != NULL) {
\r
7609 free(history[histIn]);
\r
7610 history[histIn] = NULL;
\r
7612 if (*cmd == NULLCHAR) return;
\r
7613 history[histIn] = StrSave(cmd);
\r
7614 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7615 if (history[histIn] != NULL) {
\r
7616 free(history[histIn]);
\r
7617 history[histIn] = NULL;
\r
7623 PrevInHistory(char *cmd)
\r
7626 if (histP == histIn) {
\r
7627 if (history[histIn] != NULL) free(history[histIn]);
\r
7628 history[histIn] = StrSave(cmd);
\r
7630 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7631 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7633 return history[histP];
\r
7639 if (histP == histIn) return NULL;
\r
7640 histP = (histP + 1) % HISTORY_SIZE;
\r
7641 return history[histP];
\r
7648 BOOLEAN immediate;
\r
7649 } IcsTextMenuEntry;
\r
7650 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7651 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7654 ParseIcsTextMenu(char *icsTextMenuString)
\r
7657 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7658 char *p = icsTextMenuString;
\r
7659 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7662 if (e->command != NULL) {
\r
7664 e->command = NULL;
\r
7668 e = icsTextMenuEntry;
\r
7669 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7670 if (*p == ';' || *p == '\n') {
\r
7671 e->item = strdup("-");
\r
7672 e->command = NULL;
\r
7674 } else if (*p == '-') {
\r
7675 e->item = strdup("-");
\r
7676 e->command = NULL;
\r
7680 char *q, *r, *s, *t;
\r
7682 q = strchr(p, ',');
\r
7683 if (q == NULL) break;
\r
7685 r = strchr(q + 1, ',');
\r
7686 if (r == NULL) break;
\r
7688 s = strchr(r + 1, ',');
\r
7689 if (s == NULL) break;
\r
7692 t = strchr(s + 1, c);
\r
7695 t = strchr(s + 1, c);
\r
7697 if (t != NULL) *t = NULLCHAR;
\r
7698 e->item = strdup(p);
\r
7699 e->command = strdup(q + 1);
\r
7700 e->getname = *(r + 1) != '0';
\r
7701 e->immediate = *(s + 1) != '0';
\r
7705 if (t == NULL) break;
\r
7714 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7718 hmenu = LoadMenu(hInst, "TextMenu");
\r
7719 h = GetSubMenu(hmenu, 0);
\r
7721 if (strcmp(e->item, "-") == 0) {
\r
7722 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7724 if (e->item[0] == '|') {
\r
7725 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7726 IDM_CommandX + i, &e->item[1]);
\r
7728 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7737 WNDPROC consoleTextWindowProc;
\r
7740 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7742 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7743 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7747 SetWindowText(hInput, command);
\r
7749 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7751 sel.cpMin = 999999;
\r
7752 sel.cpMax = 999999;
\r
7753 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7758 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7759 if (sel.cpMin == sel.cpMax) {
\r
7760 /* Expand to surrounding word */
\r
7763 tr.chrg.cpMax = sel.cpMin;
\r
7764 tr.chrg.cpMin = --sel.cpMin;
\r
7765 if (sel.cpMin < 0) break;
\r
7766 tr.lpstrText = name;
\r
7767 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7768 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7772 tr.chrg.cpMin = sel.cpMax;
\r
7773 tr.chrg.cpMax = ++sel.cpMax;
\r
7774 tr.lpstrText = name;
\r
7775 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7776 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7779 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7780 MessageBeep(MB_ICONEXCLAMATION);
\r
7784 tr.lpstrText = name;
\r
7785 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7787 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7788 MessageBeep(MB_ICONEXCLAMATION);
\r
7791 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7794 sprintf(buf, "%s %s", command, name);
\r
7795 SetWindowText(hInput, buf);
\r
7796 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7798 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7799 SetWindowText(hInput, buf);
\r
7800 sel.cpMin = 999999;
\r
7801 sel.cpMax = 999999;
\r
7802 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7808 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7813 switch (message) {
\r
7815 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7818 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7821 sel.cpMin = 999999;
\r
7822 sel.cpMax = 999999;
\r
7823 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7824 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7829 if(wParam != '\022') {
\r
7830 if (wParam == '\t') {
\r
7831 if (GetKeyState(VK_SHIFT) < 0) {
\r
7833 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7834 if (buttonDesc[0].hwnd) {
\r
7835 SetFocus(buttonDesc[0].hwnd);
\r
7837 SetFocus(hwndMain);
\r
7841 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7844 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7845 JAWS_DELETE( SetFocus(hInput); )
\r
7846 SendMessage(hInput, message, wParam, lParam);
\r
7849 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7850 case WM_RBUTTONUP:
\r
7851 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7852 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7853 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7856 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7857 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7858 if (sel.cpMin == sel.cpMax) {
\r
7859 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7860 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7862 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7863 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7865 pt.x = LOWORD(lParam);
\r
7866 pt.y = HIWORD(lParam);
\r
7867 MenuPopup(hwnd, pt, hmenu, -1);
\r
7871 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7873 return SendMessage(hInput, message, wParam, lParam);
\r
7874 case WM_MBUTTONDOWN:
\r
7875 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7876 case WM_RBUTTONDOWN:
\r
7877 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7878 /* Move selection here if it was empty */
\r
7880 pt.x = LOWORD(lParam);
\r
7881 pt.y = HIWORD(lParam);
\r
7882 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7883 if (sel.cpMin == sel.cpMax) {
\r
7884 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7885 sel.cpMax = sel.cpMin;
\r
7886 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7888 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7892 switch (LOWORD(wParam)) {
\r
7893 case IDM_QuickPaste:
\r
7895 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7896 if (sel.cpMin == sel.cpMax) {
\r
7897 MessageBeep(MB_ICONEXCLAMATION);
\r
7900 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7901 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7902 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7907 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7910 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7913 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7917 int i = LOWORD(wParam) - IDM_CommandX;
\r
7918 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7919 icsTextMenuEntry[i].command != NULL) {
\r
7920 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7921 icsTextMenuEntry[i].getname,
\r
7922 icsTextMenuEntry[i].immediate);
\r
7930 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7933 WNDPROC consoleInputWindowProc;
\r
7936 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7938 char buf[MSG_SIZ];
\r
7940 static BOOL sendNextChar = FALSE;
\r
7941 static BOOL quoteNextChar = FALSE;
\r
7942 InputSource *is = consoleInputSource;
\r
7946 switch (message) {
\r
7948 if (!appData.localLineEditing || sendNextChar) {
\r
7949 is->buf[0] = (CHAR) wParam;
\r
7951 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7952 sendNextChar = FALSE;
\r
7955 if (quoteNextChar) {
\r
7956 buf[0] = (char) wParam;
\r
7957 buf[1] = NULLCHAR;
\r
7958 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7959 quoteNextChar = FALSE;
\r
7963 case '\r': /* Enter key */
\r
7964 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7965 if (consoleEcho) SaveInHistory(is->buf);
\r
7966 is->buf[is->count++] = '\n';
\r
7967 is->buf[is->count] = NULLCHAR;
\r
7968 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7969 if (consoleEcho) {
\r
7970 ConsoleOutput(is->buf, is->count, TRUE);
\r
7971 } else if (appData.localLineEditing) {
\r
7972 ConsoleOutput("\n", 1, TRUE);
\r
7975 case '\033': /* Escape key */
\r
7976 SetWindowText(hwnd, "");
\r
7977 cf.cbSize = sizeof(CHARFORMAT);
\r
7978 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7979 if (consoleEcho) {
\r
7980 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7982 cf.crTextColor = COLOR_ECHOOFF;
\r
7984 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7985 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7987 case '\t': /* Tab key */
\r
7988 if (GetKeyState(VK_SHIFT) < 0) {
\r
7990 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7993 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7994 if (buttonDesc[0].hwnd) {
\r
7995 SetFocus(buttonDesc[0].hwnd);
\r
7997 SetFocus(hwndMain);
\r
8001 case '\023': /* Ctrl+S */
\r
8002 sendNextChar = TRUE;
\r
8004 case '\021': /* Ctrl+Q */
\r
8005 quoteNextChar = TRUE;
\r
8015 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8016 p = PrevInHistory(buf);
\r
8018 SetWindowText(hwnd, p);
\r
8019 sel.cpMin = 999999;
\r
8020 sel.cpMax = 999999;
\r
8021 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8026 p = NextInHistory();
\r
8028 SetWindowText(hwnd, p);
\r
8029 sel.cpMin = 999999;
\r
8030 sel.cpMax = 999999;
\r
8031 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8037 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8041 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8045 case WM_MBUTTONDOWN:
\r
8046 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8047 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8049 case WM_RBUTTONUP:
\r
8050 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8051 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8052 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8056 hmenu = LoadMenu(hInst, "InputMenu");
\r
8057 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8058 if (sel.cpMin == sel.cpMax) {
\r
8059 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8060 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8062 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8063 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8065 pt.x = LOWORD(lParam);
\r
8066 pt.y = HIWORD(lParam);
\r
8067 MenuPopup(hwnd, pt, hmenu, -1);
\r
8071 switch (LOWORD(wParam)) {
\r
8073 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8075 case IDM_SelectAll:
\r
8077 sel.cpMax = -1; /*999999?*/
\r
8078 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8081 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8084 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8087 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8092 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8095 #define CO_MAX 100000
\r
8096 #define CO_TRIM 1000
\r
8099 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8101 static SnapData sd;
\r
8102 static HWND hText, hInput /*, hFocus*/;
\r
8103 // InputSource *is = consoleInputSource;
\r
8105 static int sizeX, sizeY;
\r
8106 int newSizeX, newSizeY;
\r
8109 switch (message) {
\r
8111 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8113 ENLINK *pLink = (ENLINK*)lParam;
\r
8114 if (pLink->msg == WM_LBUTTONUP)
\r
8118 tr.chrg = pLink->chrg;
\r
8119 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8120 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8121 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8122 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8123 free(tr.lpstrText);
\r
8127 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8128 hwndConsole = hDlg;
\r
8129 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8130 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8132 consoleTextWindowProc = (WNDPROC)
\r
8133 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8134 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8135 consoleInputWindowProc = (WNDPROC)
\r
8136 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8137 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8138 Colorize(ColorNormal, TRUE);
\r
8139 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8140 ChangedConsoleFont();
\r
8141 GetClientRect(hDlg, &rect);
\r
8142 sizeX = rect.right;
\r
8143 sizeY = rect.bottom;
\r
8144 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8145 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8146 WINDOWPLACEMENT wp;
\r
8147 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8148 wp.length = sizeof(WINDOWPLACEMENT);
\r
8150 wp.showCmd = SW_SHOW;
\r
8151 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8152 wp.rcNormalPosition.left = wpConsole.x;
\r
8153 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8154 wp.rcNormalPosition.top = wpConsole.y;
\r
8155 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8156 SetWindowPlacement(hDlg, &wp);
\r
8159 // [HGM] Chessknight's change 2004-07-13
\r
8160 else { /* Determine Defaults */
\r
8161 WINDOWPLACEMENT wp;
\r
8162 wpConsole.x = winWidth + 1;
\r
8163 wpConsole.y = boardY;
\r
8164 wpConsole.width = screenWidth - winWidth;
\r
8165 wpConsole.height = winHeight;
\r
8166 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8167 wp.length = sizeof(WINDOWPLACEMENT);
\r
8169 wp.showCmd = SW_SHOW;
\r
8170 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8171 wp.rcNormalPosition.left = wpConsole.x;
\r
8172 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8173 wp.rcNormalPosition.top = wpConsole.y;
\r
8174 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8175 SetWindowPlacement(hDlg, &wp);
\r
8190 if (IsIconic(hDlg)) break;
\r
8191 newSizeX = LOWORD(lParam);
\r
8192 newSizeY = HIWORD(lParam);
\r
8193 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8194 RECT rectText, rectInput;
\r
8196 int newTextHeight, newTextWidth;
\r
8197 GetWindowRect(hText, &rectText);
\r
8198 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8199 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8200 if (newTextHeight < 0) {
\r
8201 newSizeY += -newTextHeight;
\r
8202 newTextHeight = 0;
\r
8204 SetWindowPos(hText, NULL, 0, 0,
\r
8205 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8206 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8207 pt.x = rectInput.left;
\r
8208 pt.y = rectInput.top + newSizeY - sizeY;
\r
8209 ScreenToClient(hDlg, &pt);
\r
8210 SetWindowPos(hInput, NULL,
\r
8211 pt.x, pt.y, /* needs client coords */
\r
8212 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8213 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8219 case WM_GETMINMAXINFO:
\r
8220 /* Prevent resizing window too small */
\r
8221 mmi = (MINMAXINFO *) lParam;
\r
8222 mmi->ptMinTrackSize.x = 100;
\r
8223 mmi->ptMinTrackSize.y = 100;
\r
8226 /* [AS] Snapping */
\r
8227 case WM_ENTERSIZEMOVE:
\r
8228 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8231 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8234 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8236 case WM_EXITSIZEMOVE:
\r
8237 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8240 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8247 HWND hCons, hText;
\r
8249 if (hwndConsole) return;
\r
8250 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8251 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8254 // make the text item in the console do URL links
\r
8255 hText = GetDlgItem(hCons, OPT_ConsoleText);
\r
8256 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8257 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8258 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8263 ConsoleOutput(char* data, int length, int forceVisible)
\r
8268 char buf[CO_MAX+1];
\r
8271 static int delayLF = 0;
\r
8272 CHARRANGE savesel, sel;
\r
8274 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8282 while (length--) {
\r
8290 } else if (*p == '\007') {
\r
8291 MyPlaySound(&sounds[(int)SoundBell]);
\r
8298 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8299 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8300 /* Save current selection */
\r
8301 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8302 exlen = GetWindowTextLength(hText);
\r
8303 /* Find out whether current end of text is visible */
\r
8304 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8305 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8306 /* Trim existing text if it's too long */
\r
8307 if (exlen + (q - buf) > CO_MAX) {
\r
8308 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8311 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8312 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8314 savesel.cpMin -= trim;
\r
8315 savesel.cpMax -= trim;
\r
8316 if (exlen < 0) exlen = 0;
\r
8317 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8318 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8320 /* Append the new text */
\r
8321 sel.cpMin = exlen;
\r
8322 sel.cpMax = exlen;
\r
8323 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8324 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8325 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8326 if (forceVisible || exlen == 0 ||
\r
8327 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8328 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8329 /* Scroll to make new end of text visible if old end of text
\r
8330 was visible or new text is an echo of user typein */
\r
8331 sel.cpMin = 9999999;
\r
8332 sel.cpMax = 9999999;
\r
8333 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8334 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8335 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8336 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8338 if (savesel.cpMax == exlen || forceVisible) {
\r
8339 /* Move insert point to new end of text if it was at the old
\r
8340 end of text or if the new text is an echo of user typein */
\r
8341 sel.cpMin = 9999999;
\r
8342 sel.cpMax = 9999999;
\r
8343 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8345 /* Restore previous selection */
\r
8346 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8348 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8355 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8359 COLORREF oldFg, oldBg;
\r
8363 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8365 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8366 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8367 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8370 rect.right = x + squareSize;
\r
8372 rect.bottom = y + squareSize;
\r
8375 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8376 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8377 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8378 &rect, str, strlen(str), NULL);
\r
8380 (void) SetTextColor(hdc, oldFg);
\r
8381 (void) SetBkColor(hdc, oldBg);
\r
8382 (void) SelectObject(hdc, oldFont);
\r
8386 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8387 RECT *rect, char *color, char *flagFell)
\r
8391 COLORREF oldFg, oldBg;
\r
8394 if (appData.clockMode) {
\r
8396 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8398 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8405 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8406 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8408 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8409 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8411 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8415 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8416 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8417 rect, str, strlen(str), NULL);
\r
8418 if(logoHeight > 0 && appData.clockMode) {
\r
8420 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8421 r.top = rect->top + logoHeight/2;
\r
8422 r.left = rect->left;
\r
8423 r.right = rect->right;
\r
8424 r.bottom = rect->bottom;
\r
8425 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8426 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8427 &r, str, strlen(str), NULL);
\r
8429 (void) SetTextColor(hdc, oldFg);
\r
8430 (void) SetBkColor(hdc, oldBg);
\r
8431 (void) SelectObject(hdc, oldFont);
\r
8436 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8442 if( count <= 0 ) {
\r
8443 if (appData.debugMode) {
\r
8444 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8447 return ERROR_INVALID_USER_BUFFER;
\r
8450 ResetEvent(ovl->hEvent);
\r
8451 ovl->Offset = ovl->OffsetHigh = 0;
\r
8452 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8456 err = GetLastError();
\r
8457 if (err == ERROR_IO_PENDING) {
\r
8458 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8462 err = GetLastError();
\r
8469 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8474 ResetEvent(ovl->hEvent);
\r
8475 ovl->Offset = ovl->OffsetHigh = 0;
\r
8476 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8480 err = GetLastError();
\r
8481 if (err == ERROR_IO_PENDING) {
\r
8482 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8486 err = GetLastError();
\r
8492 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8493 void CheckForInputBufferFull( InputSource * is )
\r
8495 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8496 /* Look for end of line */
\r
8497 char * p = is->buf;
\r
8499 while( p < is->next && *p != '\n' ) {
\r
8503 if( p >= is->next ) {
\r
8504 if (appData.debugMode) {
\r
8505 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8508 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8509 is->count = (DWORD) -1;
\r
8510 is->next = is->buf;
\r
8516 InputThread(LPVOID arg)
\r
8521 is = (InputSource *) arg;
\r
8522 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8523 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8524 while (is->hThread != NULL) {
\r
8525 is->error = DoReadFile(is->hFile, is->next,
\r
8526 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8527 &is->count, &ovl);
\r
8528 if (is->error == NO_ERROR) {
\r
8529 is->next += is->count;
\r
8531 if (is->error == ERROR_BROKEN_PIPE) {
\r
8532 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8535 is->count = (DWORD) -1;
\r
8536 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8541 CheckForInputBufferFull( is );
\r
8543 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8545 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8547 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8550 CloseHandle(ovl.hEvent);
\r
8551 CloseHandle(is->hFile);
\r
8553 if (appData.debugMode) {
\r
8554 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8561 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8563 NonOvlInputThread(LPVOID arg)
\r
8570 is = (InputSource *) arg;
\r
8571 while (is->hThread != NULL) {
\r
8572 is->error = ReadFile(is->hFile, is->next,
\r
8573 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8574 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8575 if (is->error == NO_ERROR) {
\r
8576 /* Change CRLF to LF */
\r
8577 if (is->next > is->buf) {
\r
8579 i = is->count + 1;
\r
8587 if (prev == '\r' && *p == '\n') {
\r
8599 if (is->error == ERROR_BROKEN_PIPE) {
\r
8600 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8603 is->count = (DWORD) -1;
\r
8607 CheckForInputBufferFull( is );
\r
8609 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8611 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8613 if (is->count < 0) break; /* Quit on error */
\r
8615 CloseHandle(is->hFile);
\r
8620 SocketInputThread(LPVOID arg)
\r
8624 is = (InputSource *) arg;
\r
8625 while (is->hThread != NULL) {
\r
8626 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8627 if ((int)is->count == SOCKET_ERROR) {
\r
8628 is->count = (DWORD) -1;
\r
8629 is->error = WSAGetLastError();
\r
8631 is->error = NO_ERROR;
\r
8632 is->next += is->count;
\r
8633 if (is->count == 0 && is->second == is) {
\r
8634 /* End of file on stderr; quit with no message */
\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 EOF or error */
\r
8648 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8652 is = (InputSource *) lParam;
\r
8653 if (is->lineByLine) {
\r
8654 /* Feed in lines one by one */
\r
8655 char *p = is->buf;
\r
8657 while (q < is->next) {
\r
8658 if (*q++ == '\n') {
\r
8659 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8664 /* Move any partial line to the start of the buffer */
\r
8666 while (p < is->next) {
\r
8671 if (is->error != NO_ERROR || is->count == 0) {
\r
8672 /* Notify backend of the error. Note: If there was a partial
\r
8673 line at the end, it is not flushed through. */
\r
8674 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8677 /* Feed in the whole chunk of input at once */
\r
8678 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8679 is->next = is->buf;
\r
8683 /*---------------------------------------------------------------------------*\
\r
8685 * Menu enables. Used when setting various modes.
\r
8687 \*---------------------------------------------------------------------------*/
\r
8695 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8697 while (enab->item > 0) {
\r
8698 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8703 Enables gnuEnables[] = {
\r
8704 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8705 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8706 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8707 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8708 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8709 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8710 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8711 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8712 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8713 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8717 Enables icsEnables[] = {
\r
8718 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8719 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8720 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8721 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8722 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8723 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8724 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8725 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8726 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8727 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8728 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8729 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8734 Enables zippyEnables[] = {
\r
8735 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8736 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8737 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8742 Enables ncpEnables[] = {
\r
8743 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8744 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8745 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8746 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8747 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8748 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8752 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8761 Enables trainingOnEnables[] = {
\r
8762 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8763 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8764 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8765 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8766 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8767 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8768 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8769 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8773 Enables trainingOffEnables[] = {
\r
8774 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8775 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8776 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8777 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8778 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8779 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8780 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8781 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8785 /* These modify either ncpEnables or gnuEnables */
\r
8786 Enables cmailEnables[] = {
\r
8787 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8788 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8789 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8790 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8792 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8797 Enables machineThinkingEnables[] = {
\r
8798 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8816 Enables userThinkingEnables[] = {
\r
8817 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8819 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8820 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8821 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8822 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8823 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8824 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8825 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8826 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8827 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8828 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8829 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8830 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8831 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8835 /*---------------------------------------------------------------------------*\
\r
8837 * Front-end interface functions exported by XBoard.
\r
8838 * Functions appear in same order as prototypes in frontend.h.
\r
8840 \*---------------------------------------------------------------------------*/
\r
8844 static UINT prevChecked = 0;
\r
8845 static int prevPausing = 0;
\r
8848 if (pausing != prevPausing) {
\r
8849 prevPausing = pausing;
\r
8850 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8851 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8852 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8855 switch (gameMode) {
\r
8856 case BeginningOfGame:
\r
8857 if (appData.icsActive)
\r
8858 nowChecked = IDM_IcsClient;
\r
8859 else if (appData.noChessProgram)
\r
8860 nowChecked = IDM_EditGame;
\r
8862 nowChecked = IDM_MachineBlack;
\r
8864 case MachinePlaysBlack:
\r
8865 nowChecked = IDM_MachineBlack;
\r
8867 case MachinePlaysWhite:
\r
8868 nowChecked = IDM_MachineWhite;
\r
8870 case TwoMachinesPlay:
\r
8871 nowChecked = IDM_TwoMachines;
\r
8874 nowChecked = IDM_AnalysisMode;
\r
8877 nowChecked = IDM_AnalyzeFile;
\r
8880 nowChecked = IDM_EditGame;
\r
8882 case PlayFromGameFile:
\r
8883 nowChecked = IDM_LoadGame;
\r
8885 case EditPosition:
\r
8886 nowChecked = IDM_EditPosition;
\r
8889 nowChecked = IDM_Training;
\r
8891 case IcsPlayingWhite:
\r
8892 case IcsPlayingBlack:
\r
8893 case IcsObserving:
\r
8895 nowChecked = IDM_IcsClient;
\r
8902 if (prevChecked != 0)
\r
8903 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8904 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8905 if (nowChecked != 0)
\r
8906 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8907 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8909 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8910 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8911 MF_BYCOMMAND|MF_ENABLED);
\r
8913 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8914 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8917 prevChecked = nowChecked;
\r
8919 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8920 if (appData.icsActive) {
\r
8921 if (appData.icsEngineAnalyze) {
\r
8922 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8923 MF_BYCOMMAND|MF_CHECKED);
\r
8925 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8926 MF_BYCOMMAND|MF_UNCHECKED);
\r
8934 HMENU hmenu = GetMenu(hwndMain);
\r
8935 SetMenuEnables(hmenu, icsEnables);
\r
8936 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8937 MF_BYPOSITION|MF_ENABLED);
\r
8939 if (appData.zippyPlay) {
\r
8940 SetMenuEnables(hmenu, zippyEnables);
\r
8941 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8942 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8943 MF_BYCOMMAND|MF_ENABLED);
\r
8951 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8957 HMENU hmenu = GetMenu(hwndMain);
\r
8958 SetMenuEnables(hmenu, ncpEnables);
\r
8959 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8960 MF_BYPOSITION|MF_GRAYED);
\r
8961 DrawMenuBar(hwndMain);
\r
8967 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8971 SetTrainingModeOn()
\r
8974 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8975 for (i = 0; i < N_BUTTONS; i++) {
\r
8976 if (buttonDesc[i].hwnd != NULL)
\r
8977 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8982 VOID SetTrainingModeOff()
\r
8985 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8986 for (i = 0; i < N_BUTTONS; i++) {
\r
8987 if (buttonDesc[i].hwnd != NULL)
\r
8988 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8994 SetUserThinkingEnables()
\r
8996 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9000 SetMachineThinkingEnables()
\r
9002 HMENU hMenu = GetMenu(hwndMain);
\r
9003 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9005 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9007 if (gameMode == MachinePlaysBlack) {
\r
9008 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9009 } else if (gameMode == MachinePlaysWhite) {
\r
9010 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9011 } else if (gameMode == TwoMachinesPlay) {
\r
9012 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9018 DisplayTitle(char *str)
\r
9020 char title[MSG_SIZ], *host;
\r
9021 if (str[0] != NULLCHAR) {
\r
9022 strcpy(title, str);
\r
9023 } else if (appData.icsActive) {
\r
9024 if (appData.icsCommPort[0] != NULLCHAR)
\r
9027 host = appData.icsHost;
\r
9028 sprintf(title, "%s: %s", szTitle, host);
\r
9029 } else if (appData.noChessProgram) {
\r
9030 strcpy(title, szTitle);
\r
9032 strcpy(title, szTitle);
\r
9033 strcat(title, ": ");
\r
9034 strcat(title, first.tidy);
\r
9036 SetWindowText(hwndMain, title);
\r
9041 DisplayMessage(char *str1, char *str2)
\r
9045 int remain = MESSAGE_TEXT_MAX - 1;
\r
9048 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9049 messageText[0] = NULLCHAR;
\r
9051 len = strlen(str1);
\r
9052 if (len > remain) len = remain;
\r
9053 strncpy(messageText, str1, len);
\r
9054 messageText[len] = NULLCHAR;
\r
9057 if (*str2 && remain >= 2) {
\r
9059 strcat(messageText, " ");
\r
9062 len = strlen(str2);
\r
9063 if (len > remain) len = remain;
\r
9064 strncat(messageText, str2, len);
\r
9066 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9068 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9072 hdc = GetDC(hwndMain);
\r
9073 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9074 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9075 &messageRect, messageText, strlen(messageText), NULL);
\r
9076 (void) SelectObject(hdc, oldFont);
\r
9077 (void) ReleaseDC(hwndMain, hdc);
\r
9081 DisplayError(char *str, int error)
\r
9083 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9089 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9090 NULL, error, LANG_NEUTRAL,
\r
9091 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9093 sprintf(buf, "%s:\n%s", str, buf2);
\r
9095 ErrorMap *em = errmap;
\r
9096 while (em->err != 0 && em->err != error) em++;
\r
9097 if (em->err != 0) {
\r
9098 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9100 sprintf(buf, "%s:\nError code %d", str, error);
\r
9105 ErrorPopUp("Error", buf);
\r
9110 DisplayMoveError(char *str)
\r
9112 fromX = fromY = -1;
\r
9113 ClearHighlights();
\r
9114 DrawPosition(FALSE, NULL);
\r
9115 if (appData.popupMoveErrors) {
\r
9116 ErrorPopUp("Error", str);
\r
9118 DisplayMessage(str, "");
\r
9119 moveErrorMessageUp = TRUE;
\r
9124 DisplayFatalError(char *str, int error, int exitStatus)
\r
9126 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9128 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9131 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9132 NULL, error, LANG_NEUTRAL,
\r
9133 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9135 sprintf(buf, "%s:\n%s", str, buf2);
\r
9137 ErrorMap *em = errmap;
\r
9138 while (em->err != 0 && em->err != error) em++;
\r
9139 if (em->err != 0) {
\r
9140 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9142 sprintf(buf, "%s:\nError code %d", str, error);
\r
9147 if (appData.debugMode) {
\r
9148 fprintf(debugFP, "%s: %s\n", label, str);
\r
9150 if (appData.popupExitMessage) {
\r
9151 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9152 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9154 ExitEvent(exitStatus);
\r
9159 DisplayInformation(char *str)
\r
9161 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9166 DisplayNote(char *str)
\r
9168 ErrorPopUp("Note", str);
\r
9173 char *title, *question, *replyPrefix;
\r
9178 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9180 static QuestionParams *qp;
\r
9181 char reply[MSG_SIZ];
\r
9184 switch (message) {
\r
9185 case WM_INITDIALOG:
\r
9186 qp = (QuestionParams *) lParam;
\r
9187 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9188 SetWindowText(hDlg, qp->title);
\r
9189 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9190 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9194 switch (LOWORD(wParam)) {
\r
9196 strcpy(reply, qp->replyPrefix);
\r
9197 if (*reply) strcat(reply, " ");
\r
9198 len = strlen(reply);
\r
9199 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9200 strcat(reply, "\n");
\r
9201 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9202 EndDialog(hDlg, TRUE);
\r
9203 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9206 EndDialog(hDlg, FALSE);
\r
9217 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9219 QuestionParams qp;
\r
9223 qp.question = question;
\r
9224 qp.replyPrefix = replyPrefix;
\r
9226 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9227 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9228 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9229 FreeProcInstance(lpProc);
\r
9232 /* [AS] Pick FRC position */
\r
9233 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9235 static int * lpIndexFRC;
\r
9241 case WM_INITDIALOG:
\r
9242 lpIndexFRC = (int *) lParam;
\r
9244 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9246 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9247 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9248 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9249 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9254 switch( LOWORD(wParam) ) {
\r
9256 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9257 EndDialog( hDlg, 0 );
\r
9258 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9261 EndDialog( hDlg, 1 );
\r
9263 case IDC_NFG_Edit:
\r
9264 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9265 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9267 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9270 case IDC_NFG_Random:
\r
9271 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9272 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9285 int index = appData.defaultFrcPosition;
\r
9286 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9288 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9290 if( result == 0 ) {
\r
9291 appData.defaultFrcPosition = index;
\r
9297 /* [AS] Game list options */
\r
9303 static GLT_Item GLT_ItemInfo[] = {
\r
9304 { GLT_EVENT, "Event" },
\r
9305 { GLT_SITE, "Site" },
\r
9306 { GLT_DATE, "Date" },
\r
9307 { GLT_ROUND, "Round" },
\r
9308 { GLT_PLAYERS, "Players" },
\r
9309 { GLT_RESULT, "Result" },
\r
9310 { GLT_WHITE_ELO, "White Rating" },
\r
9311 { GLT_BLACK_ELO, "Black Rating" },
\r
9312 { GLT_TIME_CONTROL,"Time Control" },
\r
9313 { GLT_VARIANT, "Variant" },
\r
9314 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9315 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9319 const char * GLT_FindItem( char id )
\r
9321 const char * result = 0;
\r
9323 GLT_Item * list = GLT_ItemInfo;
\r
9325 while( list->id != 0 ) {
\r
9326 if( list->id == id ) {
\r
9327 result = list->name;
\r
9337 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9339 const char * name = GLT_FindItem( id );
\r
9342 if( index >= 0 ) {
\r
9343 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9346 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9351 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9355 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9358 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9362 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9364 pc = GLT_ALL_TAGS;
\r
9367 if( strchr( tags, *pc ) == 0 ) {
\r
9368 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9373 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9376 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9378 char result = '\0';
\r
9381 GLT_Item * list = GLT_ItemInfo;
\r
9383 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9384 while( list->id != 0 ) {
\r
9385 if( strcmp( list->name, name ) == 0 ) {
\r
9386 result = list->id;
\r
9397 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9399 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9400 int idx2 = idx1 + delta;
\r
9401 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9403 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9406 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9407 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9408 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9409 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9413 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9415 static char glt[64];
\r
9416 static char * lpUserGLT;
\r
9420 case WM_INITDIALOG:
\r
9421 lpUserGLT = (char *) lParam;
\r
9423 strcpy( glt, lpUserGLT );
\r
9425 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9427 /* Initialize list */
\r
9428 GLT_TagsToList( hDlg, glt );
\r
9430 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9435 switch( LOWORD(wParam) ) {
\r
9438 char * pc = lpUserGLT;
\r
9440 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9444 id = GLT_ListItemToTag( hDlg, idx );
\r
9448 } while( id != '\0' );
\r
9450 EndDialog( hDlg, 0 );
\r
9453 EndDialog( hDlg, 1 );
\r
9456 case IDC_GLT_Default:
\r
9457 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9458 GLT_TagsToList( hDlg, glt );
\r
9461 case IDC_GLT_Restore:
\r
9462 strcpy( glt, lpUserGLT );
\r
9463 GLT_TagsToList( hDlg, glt );
\r
9467 GLT_MoveSelection( hDlg, -1 );
\r
9470 case IDC_GLT_Down:
\r
9471 GLT_MoveSelection( hDlg, +1 );
\r
9481 int GameListOptions()
\r
9485 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9487 strcpy( glt, appData.gameListTags );
\r
9489 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9491 if( result == 0 ) {
\r
9492 /* [AS] Memory leak here! */
\r
9493 appData.gameListTags = strdup( glt );
\r
9501 DisplayIcsInteractionTitle(char *str)
\r
9503 char consoleTitle[MSG_SIZ];
\r
9505 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9506 SetWindowText(hwndConsole, consoleTitle);
\r
9510 DrawPosition(int fullRedraw, Board board)
\r
9512 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9519 fromX = fromY = -1;
\r
9520 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9521 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9522 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9523 dragInfo.lastpos = dragInfo.pos;
\r
9524 dragInfo.start.x = dragInfo.start.y = -1;
\r
9525 dragInfo.from = dragInfo.start;
\r
9527 DrawPosition(TRUE, NULL);
\r
9533 CommentPopUp(char *title, char *str)
\r
9535 HWND hwnd = GetActiveWindow();
\r
9536 EitherCommentPopUp(0, title, str, FALSE);
\r
9538 SetActiveWindow(hwnd);
\r
9542 CommentPopDown(void)
\r
9544 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9545 if (commentDialog) {
\r
9546 ShowWindow(commentDialog, SW_HIDE);
\r
9548 commentDialogUp = FALSE;
\r
9552 EditCommentPopUp(int index, char *title, char *str)
\r
9554 EitherCommentPopUp(index, title, str, TRUE);
\r
9561 MyPlaySound(&sounds[(int)SoundMove]);
\r
9564 VOID PlayIcsWinSound()
\r
9566 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9569 VOID PlayIcsLossSound()
\r
9571 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9574 VOID PlayIcsDrawSound()
\r
9576 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9579 VOID PlayIcsUnfinishedSound()
\r
9581 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9587 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9595 consoleEcho = TRUE;
\r
9596 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9597 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9598 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9607 consoleEcho = FALSE;
\r
9608 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9609 /* This works OK: set text and background both to the same color */
\r
9611 cf.crTextColor = COLOR_ECHOOFF;
\r
9612 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9613 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9616 /* No Raw()...? */
\r
9618 void Colorize(ColorClass cc, int continuation)
\r
9620 currentColorClass = cc;
\r
9621 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9622 consoleCF.crTextColor = textAttribs[cc].color;
\r
9623 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9624 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9630 static char buf[MSG_SIZ];
\r
9631 DWORD bufsiz = MSG_SIZ;
\r
9633 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9634 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9636 if (!GetUserName(buf, &bufsiz)) {
\r
9637 /*DisplayError("Error getting user name", GetLastError());*/
\r
9638 strcpy(buf, "User");
\r
9646 static char buf[MSG_SIZ];
\r
9647 DWORD bufsiz = MSG_SIZ;
\r
9649 if (!GetComputerName(buf, &bufsiz)) {
\r
9650 /*DisplayError("Error getting host name", GetLastError());*/
\r
9651 strcpy(buf, "Unknown");
\r
9658 ClockTimerRunning()
\r
9660 return clockTimerEvent != 0;
\r
9666 if (clockTimerEvent == 0) return FALSE;
\r
9667 KillTimer(hwndMain, clockTimerEvent);
\r
9668 clockTimerEvent = 0;
\r
9673 StartClockTimer(long millisec)
\r
9675 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9676 (UINT) millisec, NULL);
\r
9680 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9683 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9685 if(appData.noGUI) return;
\r
9686 hdc = GetDC(hwndMain);
\r
9687 if (!IsIconic(hwndMain)) {
\r
9688 DisplayAClock(hdc, timeRemaining, highlight,
\r
9689 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9691 if (highlight && iconCurrent == iconBlack) {
\r
9692 iconCurrent = iconWhite;
\r
9693 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9694 if (IsIconic(hwndMain)) {
\r
9695 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9698 (void) ReleaseDC(hwndMain, hdc);
\r
9700 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9704 DisplayBlackClock(long timeRemaining, int highlight)
\r
9707 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9709 if(appData.noGUI) return;
\r
9710 hdc = GetDC(hwndMain);
\r
9711 if (!IsIconic(hwndMain)) {
\r
9712 DisplayAClock(hdc, timeRemaining, highlight,
\r
9713 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9715 if (highlight && iconCurrent == iconWhite) {
\r
9716 iconCurrent = iconBlack;
\r
9717 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9718 if (IsIconic(hwndMain)) {
\r
9719 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9722 (void) ReleaseDC(hwndMain, hdc);
\r
9724 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9729 LoadGameTimerRunning()
\r
9731 return loadGameTimerEvent != 0;
\r
9735 StopLoadGameTimer()
\r
9737 if (loadGameTimerEvent == 0) return FALSE;
\r
9738 KillTimer(hwndMain, loadGameTimerEvent);
\r
9739 loadGameTimerEvent = 0;
\r
9744 StartLoadGameTimer(long millisec)
\r
9746 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9747 (UINT) millisec, NULL);
\r
9755 char fileTitle[MSG_SIZ];
\r
9757 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9758 f = OpenFileDialog(hwndMain, "a", defName,
\r
9759 appData.oldSaveStyle ? "gam" : "pgn",
\r
9761 "Save Game to File", NULL, fileTitle, NULL);
\r
9763 SaveGame(f, 0, "");
\r
9770 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9772 if (delayedTimerEvent != 0) {
\r
9773 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9774 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9776 KillTimer(hwndMain, delayedTimerEvent);
\r
9777 delayedTimerEvent = 0;
\r
9778 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9779 delayedTimerCallback();
\r
9781 delayedTimerCallback = cb;
\r
9782 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9783 (UINT) millisec, NULL);
\r
9786 DelayedEventCallback
\r
9789 if (delayedTimerEvent) {
\r
9790 return delayedTimerCallback;
\r
9797 CancelDelayedEvent()
\r
9799 if (delayedTimerEvent) {
\r
9800 KillTimer(hwndMain, delayedTimerEvent);
\r
9801 delayedTimerEvent = 0;
\r
9805 DWORD GetWin32Priority(int nice)
\r
9806 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9808 REALTIME_PRIORITY_CLASS 0x00000100
\r
9809 HIGH_PRIORITY_CLASS 0x00000080
\r
9810 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9811 NORMAL_PRIORITY_CLASS 0x00000020
\r
9812 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9813 IDLE_PRIORITY_CLASS 0x00000040
\r
9815 if (nice < -15) return 0x00000080;
\r
9816 if (nice < 0) return 0x00008000;
\r
9817 if (nice == 0) return 0x00000020;
\r
9818 if (nice < 15) return 0x00004000;
\r
9819 return 0x00000040;
\r
9822 /* Start a child process running the given program.
\r
9823 The process's standard output can be read from "from", and its
\r
9824 standard input can be written to "to".
\r
9825 Exit with fatal error if anything goes wrong.
\r
9826 Returns an opaque pointer that can be used to destroy the process
\r
9830 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9832 #define BUFSIZE 4096
\r
9834 HANDLE hChildStdinRd, hChildStdinWr,
\r
9835 hChildStdoutRd, hChildStdoutWr;
\r
9836 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9837 SECURITY_ATTRIBUTES saAttr;
\r
9839 PROCESS_INFORMATION piProcInfo;
\r
9840 STARTUPINFO siStartInfo;
\r
9842 char buf[MSG_SIZ];
\r
9845 if (appData.debugMode) {
\r
9846 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9851 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9852 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9853 saAttr.bInheritHandle = TRUE;
\r
9854 saAttr.lpSecurityDescriptor = NULL;
\r
9857 * The steps for redirecting child's STDOUT:
\r
9858 * 1. Create anonymous pipe to be STDOUT for child.
\r
9859 * 2. Create a noninheritable duplicate of read handle,
\r
9860 * and close the inheritable read handle.
\r
9863 /* Create a pipe for the child's STDOUT. */
\r
9864 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9865 return GetLastError();
\r
9868 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9869 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9870 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9871 FALSE, /* not inherited */
\r
9872 DUPLICATE_SAME_ACCESS);
\r
9874 return GetLastError();
\r
9876 CloseHandle(hChildStdoutRd);
\r
9879 * The steps for redirecting child's STDIN:
\r
9880 * 1. Create anonymous pipe to be STDIN for child.
\r
9881 * 2. Create a noninheritable duplicate of write handle,
\r
9882 * and close the inheritable write handle.
\r
9885 /* Create a pipe for the child's STDIN. */
\r
9886 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9887 return GetLastError();
\r
9890 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9891 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9892 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9893 FALSE, /* not inherited */
\r
9894 DUPLICATE_SAME_ACCESS);
\r
9896 return GetLastError();
\r
9898 CloseHandle(hChildStdinWr);
\r
9900 /* Arrange to (1) look in dir for the child .exe file, and
\r
9901 * (2) have dir be the child's working directory. Interpret
\r
9902 * dir relative to the directory WinBoard loaded from. */
\r
9903 GetCurrentDirectory(MSG_SIZ, buf);
\r
9904 SetCurrentDirectory(installDir);
\r
9905 SetCurrentDirectory(dir);
\r
9907 /* Now create the child process. */
\r
9909 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9910 siStartInfo.lpReserved = NULL;
\r
9911 siStartInfo.lpDesktop = NULL;
\r
9912 siStartInfo.lpTitle = NULL;
\r
9913 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9914 siStartInfo.cbReserved2 = 0;
\r
9915 siStartInfo.lpReserved2 = NULL;
\r
9916 siStartInfo.hStdInput = hChildStdinRd;
\r
9917 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9918 siStartInfo.hStdError = hChildStdoutWr;
\r
9920 fSuccess = CreateProcess(NULL,
\r
9921 cmdLine, /* command line */
\r
9922 NULL, /* process security attributes */
\r
9923 NULL, /* primary thread security attrs */
\r
9924 TRUE, /* handles are inherited */
\r
9925 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9926 NULL, /* use parent's environment */
\r
9928 &siStartInfo, /* STARTUPINFO pointer */
\r
9929 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9931 err = GetLastError();
\r
9932 SetCurrentDirectory(buf); /* return to prev directory */
\r
9937 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9938 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9939 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9942 /* Close the handles we don't need in the parent */
\r
9943 CloseHandle(piProcInfo.hThread);
\r
9944 CloseHandle(hChildStdinRd);
\r
9945 CloseHandle(hChildStdoutWr);
\r
9947 /* Prepare return value */
\r
9948 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9949 cp->kind = CPReal;
\r
9950 cp->hProcess = piProcInfo.hProcess;
\r
9951 cp->pid = piProcInfo.dwProcessId;
\r
9952 cp->hFrom = hChildStdoutRdDup;
\r
9953 cp->hTo = hChildStdinWrDup;
\r
9955 *pr = (void *) cp;
\r
9957 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9958 2000 where engines sometimes don't see the initial command(s)
\r
9959 from WinBoard and hang. I don't understand how that can happen,
\r
9960 but the Sleep is harmless, so I've put it in. Others have also
\r
9961 reported what may be the same problem, so hopefully this will fix
\r
9962 it for them too. */
\r
9970 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9972 ChildProc *cp; int result;
\r
9974 cp = (ChildProc *) pr;
\r
9975 if (cp == NULL) return;
\r
9977 switch (cp->kind) {
\r
9979 /* TerminateProcess is considered harmful, so... */
\r
9980 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9981 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9982 /* The following doesn't work because the chess program
\r
9983 doesn't "have the same console" as WinBoard. Maybe
\r
9984 we could arrange for this even though neither WinBoard
\r
9985 nor the chess program uses a console for stdio? */
\r
9986 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9988 /* [AS] Special termination modes for misbehaving programs... */
\r
9989 if( signal == 9 ) {
\r
9990 result = TerminateProcess( cp->hProcess, 0 );
\r
9992 if ( appData.debugMode) {
\r
9993 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9996 else if( signal == 10 ) {
\r
9997 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9999 if( dw != WAIT_OBJECT_0 ) {
\r
10000 result = TerminateProcess( cp->hProcess, 0 );
\r
10002 if ( appData.debugMode) {
\r
10003 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10009 CloseHandle(cp->hProcess);
\r
10013 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10017 closesocket(cp->sock);
\r
10022 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10023 closesocket(cp->sock);
\r
10024 closesocket(cp->sock2);
\r
10032 InterruptChildProcess(ProcRef pr)
\r
10036 cp = (ChildProc *) pr;
\r
10037 if (cp == NULL) return;
\r
10038 switch (cp->kind) {
\r
10040 /* The following doesn't work because the chess program
\r
10041 doesn't "have the same console" as WinBoard. Maybe
\r
10042 we could arrange for this even though neither WinBoard
\r
10043 nor the chess program uses a console for stdio */
\r
10044 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10049 /* Can't interrupt */
\r
10053 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10060 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10062 char cmdLine[MSG_SIZ];
\r
10064 if (port[0] == NULLCHAR) {
\r
10065 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10067 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10069 return StartChildProcess(cmdLine, "", pr);
\r
10073 /* Code to open TCP sockets */
\r
10076 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10081 struct sockaddr_in sa, mysa;
\r
10082 struct hostent FAR *hp;
\r
10083 unsigned short uport;
\r
10084 WORD wVersionRequested;
\r
10087 /* Initialize socket DLL */
\r
10088 wVersionRequested = MAKEWORD(1, 1);
\r
10089 err = WSAStartup(wVersionRequested, &wsaData);
\r
10090 if (err != 0) return err;
\r
10092 /* Make socket */
\r
10093 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10094 err = WSAGetLastError();
\r
10099 /* Bind local address using (mostly) don't-care values.
\r
10101 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10102 mysa.sin_family = AF_INET;
\r
10103 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10104 uport = (unsigned short) 0;
\r
10105 mysa.sin_port = htons(uport);
\r
10106 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10107 == SOCKET_ERROR) {
\r
10108 err = WSAGetLastError();
\r
10113 /* Resolve remote host name */
\r
10114 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10115 if (!(hp = gethostbyname(host))) {
\r
10116 unsigned int b0, b1, b2, b3;
\r
10118 err = WSAGetLastError();
\r
10120 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10121 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10122 hp->h_addrtype = AF_INET;
\r
10123 hp->h_length = 4;
\r
10124 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10125 hp->h_addr_list[0] = (char *) malloc(4);
\r
10126 hp->h_addr_list[0][0] = (char) b0;
\r
10127 hp->h_addr_list[0][1] = (char) b1;
\r
10128 hp->h_addr_list[0][2] = (char) b2;
\r
10129 hp->h_addr_list[0][3] = (char) b3;
\r
10135 sa.sin_family = hp->h_addrtype;
\r
10136 uport = (unsigned short) atoi(port);
\r
10137 sa.sin_port = htons(uport);
\r
10138 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10140 /* Make connection */
\r
10141 if (connect(s, (struct sockaddr *) &sa,
\r
10142 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10143 err = WSAGetLastError();
\r
10148 /* Prepare return value */
\r
10149 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10150 cp->kind = CPSock;
\r
10152 *pr = (ProcRef *) cp;
\r
10158 OpenCommPort(char *name, ProcRef *pr)
\r
10163 char fullname[MSG_SIZ];
\r
10165 if (*name != '\\')
\r
10166 sprintf(fullname, "\\\\.\\%s", name);
\r
10168 strcpy(fullname, name);
\r
10170 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10171 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10172 if (h == (HANDLE) -1) {
\r
10173 return GetLastError();
\r
10177 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10179 /* Accumulate characters until a 100ms pause, then parse */
\r
10180 ct.ReadIntervalTimeout = 100;
\r
10181 ct.ReadTotalTimeoutMultiplier = 0;
\r
10182 ct.ReadTotalTimeoutConstant = 0;
\r
10183 ct.WriteTotalTimeoutMultiplier = 0;
\r
10184 ct.WriteTotalTimeoutConstant = 0;
\r
10185 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10187 /* Prepare return value */
\r
10188 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10189 cp->kind = CPComm;
\r
10192 *pr = (ProcRef *) cp;
\r
10198 OpenLoopback(ProcRef *pr)
\r
10200 DisplayFatalError("Not implemented", 0, 1);
\r
10206 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10210 SOCKET s, s2, s3;
\r
10211 struct sockaddr_in sa, mysa;
\r
10212 struct hostent FAR *hp;
\r
10213 unsigned short uport;
\r
10214 WORD wVersionRequested;
\r
10217 char stderrPortStr[MSG_SIZ];
\r
10219 /* Initialize socket DLL */
\r
10220 wVersionRequested = MAKEWORD(1, 1);
\r
10221 err = WSAStartup(wVersionRequested, &wsaData);
\r
10222 if (err != 0) return err;
\r
10224 /* Resolve remote host name */
\r
10225 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10226 if (!(hp = gethostbyname(host))) {
\r
10227 unsigned int b0, b1, b2, b3;
\r
10229 err = WSAGetLastError();
\r
10231 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10232 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10233 hp->h_addrtype = AF_INET;
\r
10234 hp->h_length = 4;
\r
10235 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10236 hp->h_addr_list[0] = (char *) malloc(4);
\r
10237 hp->h_addr_list[0][0] = (char) b0;
\r
10238 hp->h_addr_list[0][1] = (char) b1;
\r
10239 hp->h_addr_list[0][2] = (char) b2;
\r
10240 hp->h_addr_list[0][3] = (char) b3;
\r
10246 sa.sin_family = hp->h_addrtype;
\r
10247 uport = (unsigned short) 514;
\r
10248 sa.sin_port = htons(uport);
\r
10249 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10251 /* Bind local socket to unused "privileged" port address
\r
10253 s = INVALID_SOCKET;
\r
10254 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10255 mysa.sin_family = AF_INET;
\r
10256 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10257 for (fromPort = 1023;; fromPort--) {
\r
10258 if (fromPort < 0) {
\r
10260 return WSAEADDRINUSE;
\r
10262 if (s == INVALID_SOCKET) {
\r
10263 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10264 err = WSAGetLastError();
\r
10269 uport = (unsigned short) fromPort;
\r
10270 mysa.sin_port = htons(uport);
\r
10271 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10272 == SOCKET_ERROR) {
\r
10273 err = WSAGetLastError();
\r
10274 if (err == WSAEADDRINUSE) continue;
\r
10278 if (connect(s, (struct sockaddr *) &sa,
\r
10279 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10280 err = WSAGetLastError();
\r
10281 if (err == WSAEADDRINUSE) {
\r
10292 /* Bind stderr local socket to unused "privileged" port address
\r
10294 s2 = INVALID_SOCKET;
\r
10295 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10296 mysa.sin_family = AF_INET;
\r
10297 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10298 for (fromPort = 1023;; fromPort--) {
\r
10299 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10300 if (fromPort < 0) {
\r
10301 (void) closesocket(s);
\r
10303 return WSAEADDRINUSE;
\r
10305 if (s2 == INVALID_SOCKET) {
\r
10306 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10307 err = WSAGetLastError();
\r
10313 uport = (unsigned short) fromPort;
\r
10314 mysa.sin_port = htons(uport);
\r
10315 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10316 == SOCKET_ERROR) {
\r
10317 err = WSAGetLastError();
\r
10318 if (err == WSAEADDRINUSE) continue;
\r
10319 (void) closesocket(s);
\r
10323 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10324 err = WSAGetLastError();
\r
10325 if (err == WSAEADDRINUSE) {
\r
10327 s2 = INVALID_SOCKET;
\r
10330 (void) closesocket(s);
\r
10331 (void) closesocket(s2);
\r
10337 prevStderrPort = fromPort; // remember port used
\r
10338 sprintf(stderrPortStr, "%d", fromPort);
\r
10340 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10341 err = WSAGetLastError();
\r
10342 (void) closesocket(s);
\r
10343 (void) closesocket(s2);
\r
10348 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10349 err = WSAGetLastError();
\r
10350 (void) closesocket(s);
\r
10351 (void) closesocket(s2);
\r
10355 if (*user == NULLCHAR) user = UserName();
\r
10356 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10357 err = WSAGetLastError();
\r
10358 (void) closesocket(s);
\r
10359 (void) closesocket(s2);
\r
10363 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10364 err = WSAGetLastError();
\r
10365 (void) closesocket(s);
\r
10366 (void) closesocket(s2);
\r
10371 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10372 err = WSAGetLastError();
\r
10373 (void) closesocket(s);
\r
10374 (void) closesocket(s2);
\r
10378 (void) closesocket(s2); /* Stop listening */
\r
10380 /* Prepare return value */
\r
10381 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10382 cp->kind = CPRcmd;
\r
10385 *pr = (ProcRef *) cp;
\r
10392 AddInputSource(ProcRef pr, int lineByLine,
\r
10393 InputCallback func, VOIDSTAR closure)
\r
10395 InputSource *is, *is2 = NULL;
\r
10396 ChildProc *cp = (ChildProc *) pr;
\r
10398 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10399 is->lineByLine = lineByLine;
\r
10401 is->closure = closure;
\r
10402 is->second = NULL;
\r
10403 is->next = is->buf;
\r
10404 if (pr == NoProc) {
\r
10405 is->kind = CPReal;
\r
10406 consoleInputSource = is;
\r
10408 is->kind = cp->kind;
\r
10410 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10411 we create all threads suspended so that the is->hThread variable can be
\r
10412 safely assigned, then let the threads start with ResumeThread.
\r
10414 switch (cp->kind) {
\r
10416 is->hFile = cp->hFrom;
\r
10417 cp->hFrom = NULL; /* now owned by InputThread */
\r
10419 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10420 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10424 is->hFile = cp->hFrom;
\r
10425 cp->hFrom = NULL; /* now owned by InputThread */
\r
10427 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10428 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10432 is->sock = cp->sock;
\r
10434 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10435 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10439 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10441 is->sock = cp->sock;
\r
10442 is->second = is2;
\r
10443 is2->sock = cp->sock2;
\r
10444 is2->second = is2;
\r
10446 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10447 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10449 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10450 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10454 if( is->hThread != NULL ) {
\r
10455 ResumeThread( is->hThread );
\r
10458 if( is2 != NULL && is2->hThread != NULL ) {
\r
10459 ResumeThread( is2->hThread );
\r
10463 return (InputSourceRef) is;
\r
10467 RemoveInputSource(InputSourceRef isr)
\r
10471 is = (InputSource *) isr;
\r
10472 is->hThread = NULL; /* tell thread to stop */
\r
10473 CloseHandle(is->hThread);
\r
10474 if (is->second != NULL) {
\r
10475 is->second->hThread = NULL;
\r
10476 CloseHandle(is->second->hThread);
\r
10482 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10485 int outCount = SOCKET_ERROR;
\r
10486 ChildProc *cp = (ChildProc *) pr;
\r
10487 static OVERLAPPED ovl;
\r
10489 if (pr == NoProc) {
\r
10490 ConsoleOutput(message, count, FALSE);
\r
10494 if (ovl.hEvent == NULL) {
\r
10495 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10497 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10499 switch (cp->kind) {
\r
10502 outCount = send(cp->sock, message, count, 0);
\r
10503 if (outCount == SOCKET_ERROR) {
\r
10504 *outError = WSAGetLastError();
\r
10506 *outError = NO_ERROR;
\r
10511 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10512 &dOutCount, NULL)) {
\r
10513 *outError = NO_ERROR;
\r
10514 outCount = (int) dOutCount;
\r
10516 *outError = GetLastError();
\r
10521 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10522 &dOutCount, &ovl);
\r
10523 if (*outError == NO_ERROR) {
\r
10524 outCount = (int) dOutCount;
\r
10532 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10535 /* Ignore delay, not implemented for WinBoard */
\r
10536 return OutputToProcess(pr, message, count, outError);
\r
10541 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10542 char *buf, int count, int error)
\r
10544 DisplayFatalError("Not implemented", 0, 1);
\r
10547 /* see wgamelist.c for Game List functions */
\r
10548 /* see wedittags.c for Edit Tags functions */
\r
10555 char buf[MSG_SIZ];
\r
10558 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10559 f = fopen(buf, "r");
\r
10561 ProcessICSInitScript(f);
\r
10569 StartAnalysisClock()
\r
10571 if (analysisTimerEvent) return;
\r
10572 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10573 (UINT) 2000, NULL);
\r
10577 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10579 static HANDLE hwndText;
\r
10581 static int sizeX, sizeY;
\r
10582 int newSizeX, newSizeY, flags;
\r
10585 switch (message) {
\r
10586 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10587 /* Initialize the dialog items */
\r
10588 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10589 SetWindowText(hDlg, analysisTitle);
\r
10590 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10591 /* Size and position the dialog */
\r
10592 if (!analysisDialog) {
\r
10593 analysisDialog = hDlg;
\r
10594 flags = SWP_NOZORDER;
\r
10595 GetClientRect(hDlg, &rect);
\r
10596 sizeX = rect.right;
\r
10597 sizeY = rect.bottom;
\r
10598 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10599 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10600 WINDOWPLACEMENT wp;
\r
10601 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10602 wp.length = sizeof(WINDOWPLACEMENT);
\r
10604 wp.showCmd = SW_SHOW;
\r
10605 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10606 wp.rcNormalPosition.left = analysisX;
\r
10607 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10608 wp.rcNormalPosition.top = analysisY;
\r
10609 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10610 SetWindowPlacement(hDlg, &wp);
\r
10612 GetClientRect(hDlg, &rect);
\r
10613 newSizeX = rect.right;
\r
10614 newSizeY = rect.bottom;
\r
10615 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10616 newSizeX, newSizeY);
\r
10617 sizeX = newSizeX;
\r
10618 sizeY = newSizeY;
\r
10623 case WM_COMMAND: /* message: received a command */
\r
10624 switch (LOWORD(wParam)) {
\r
10626 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10627 ExitAnalyzeMode();
\r
10639 newSizeX = LOWORD(lParam);
\r
10640 newSizeY = HIWORD(lParam);
\r
10641 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10642 sizeX = newSizeX;
\r
10643 sizeY = newSizeY;
\r
10646 case WM_GETMINMAXINFO:
\r
10647 /* Prevent resizing window too small */
\r
10648 mmi = (MINMAXINFO *) lParam;
\r
10649 mmi->ptMinTrackSize.x = 100;
\r
10650 mmi->ptMinTrackSize.y = 100;
\r
10657 AnalysisPopUp(char* title, char* str)
\r
10663 EngineOutputPopUp();
\r
10666 if (str == NULL) str = "";
\r
10667 p = (char *) malloc(2 * strlen(str) + 2);
\r
10670 if (*str == '\n') *q++ = '\r';
\r
10674 if (analysisText != NULL) free(analysisText);
\r
10675 analysisText = p;
\r
10677 if (analysisDialog) {
\r
10678 SetWindowText(analysisDialog, title);
\r
10679 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10680 ShowWindow(analysisDialog, SW_SHOW);
\r
10682 analysisTitle = title;
\r
10683 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10684 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10685 hwndMain, (DLGPROC)lpProc);
\r
10686 FreeProcInstance(lpProc);
\r
10688 analysisDialogUp = TRUE;
\r
10692 AnalysisPopDown()
\r
10694 if (analysisDialog) {
\r
10695 ShowWindow(analysisDialog, SW_HIDE);
\r
10697 analysisDialogUp = FALSE;
\r
10702 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10704 highlightInfo.sq[0].x = fromX;
\r
10705 highlightInfo.sq[0].y = fromY;
\r
10706 highlightInfo.sq[1].x = toX;
\r
10707 highlightInfo.sq[1].y = toY;
\r
10711 ClearHighlights()
\r
10713 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10714 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10718 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10720 premoveHighlightInfo.sq[0].x = fromX;
\r
10721 premoveHighlightInfo.sq[0].y = fromY;
\r
10722 premoveHighlightInfo.sq[1].x = toX;
\r
10723 premoveHighlightInfo.sq[1].y = toY;
\r
10727 ClearPremoveHighlights()
\r
10729 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10730 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10734 ShutDownFrontEnd()
\r
10736 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10737 DeleteClipboardTempFiles();
\r
10743 if (IsIconic(hwndMain))
\r
10744 ShowWindow(hwndMain, SW_RESTORE);
\r
10746 SetActiveWindow(hwndMain);
\r
10750 * Prototypes for animation support routines
\r
10752 static void ScreenSquare(int column, int row, POINT * pt);
\r
10753 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10754 POINT frames[], int * nFrames);
\r
10758 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10759 { // [HGM] atomic: animate blast wave
\r
10761 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10762 explodeInfo.fromX = fromX;
\r
10763 explodeInfo.fromY = fromY;
\r
10764 explodeInfo.toX = toX;
\r
10765 explodeInfo.toY = toY;
\r
10766 for(i=1; i<nFrames; i++) {
\r
10767 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10768 DrawPosition(FALSE, NULL);
\r
10769 Sleep(appData.animSpeed);
\r
10771 explodeInfo.radius = 0;
\r
10772 DrawPosition(TRUE, NULL);
\r
10775 #define kFactor 4
\r
10778 AnimateMove(board, fromX, fromY, toX, toY)
\r
10785 ChessSquare piece;
\r
10786 POINT start, finish, mid;
\r
10787 POINT frames[kFactor * 2 + 1];
\r
10790 if (!appData.animate) return;
\r
10791 if (doingSizing) return;
\r
10792 if (fromY < 0 || fromX < 0) return;
\r
10793 piece = board[fromY][fromX];
\r
10794 if (piece >= EmptySquare) return;
\r
10796 ScreenSquare(fromX, fromY, &start);
\r
10797 ScreenSquare(toX, toY, &finish);
\r
10799 /* All pieces except knights move in straight line */
\r
10800 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10801 mid.x = start.x + (finish.x - start.x) / 2;
\r
10802 mid.y = start.y + (finish.y - start.y) / 2;
\r
10804 /* Knight: make diagonal movement then straight */
\r
10805 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10806 mid.x = start.x + (finish.x - start.x) / 2;
\r
10807 mid.y = finish.y;
\r
10809 mid.x = finish.x;
\r
10810 mid.y = start.y + (finish.y - start.y) / 2;
\r
10814 /* Don't use as many frames for very short moves */
\r
10815 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10816 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10818 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10820 animInfo.from.x = fromX;
\r
10821 animInfo.from.y = fromY;
\r
10822 animInfo.to.x = toX;
\r
10823 animInfo.to.y = toY;
\r
10824 animInfo.lastpos = start;
\r
10825 animInfo.piece = piece;
\r
10826 for (n = 0; n < nFrames; n++) {
\r
10827 animInfo.pos = frames[n];
\r
10828 DrawPosition(FALSE, NULL);
\r
10829 animInfo.lastpos = animInfo.pos;
\r
10830 Sleep(appData.animSpeed);
\r
10832 animInfo.pos = finish;
\r
10833 DrawPosition(FALSE, NULL);
\r
10834 animInfo.piece = EmptySquare;
\r
10835 if(gameInfo.variant == VariantAtomic &&
\r
10836 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10837 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10840 /* Convert board position to corner of screen rect and color */
\r
10843 ScreenSquare(column, row, pt)
\r
10844 int column; int row; POINT * pt;
\r
10847 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10848 pt->y = lineGap + row * (squareSize + lineGap);
\r
10850 pt->x = lineGap + column * (squareSize + lineGap);
\r
10851 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10855 /* Generate a series of frame coords from start->mid->finish.
\r
10856 The movement rate doubles until the half way point is
\r
10857 reached, then halves back down to the final destination,
\r
10858 which gives a nice slow in/out effect. The algorithmn
\r
10859 may seem to generate too many intermediates for short
\r
10860 moves, but remember that the purpose is to attract the
\r
10861 viewers attention to the piece about to be moved and
\r
10862 then to where it ends up. Too few frames would be less
\r
10866 Tween(start, mid, finish, factor, frames, nFrames)
\r
10867 POINT * start; POINT * mid;
\r
10868 POINT * finish; int factor;
\r
10869 POINT frames[]; int * nFrames;
\r
10871 int n, fraction = 1, count = 0;
\r
10873 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10874 for (n = 0; n < factor; n++)
\r
10876 for (n = 0; n < factor; n++) {
\r
10877 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10878 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10880 fraction = fraction / 2;
\r
10884 frames[count] = *mid;
\r
10887 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10889 for (n = 0; n < factor; n++) {
\r
10890 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10891 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10893 fraction = fraction * 2;
\r
10895 *nFrames = count;
\r
10899 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10901 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10903 EvalGraphSet( first, last, current, pvInfoList );
\r
10906 void SetProgramStats( FrontEndProgramStats * stats )
\r
10908 EngineOutputUpdate( stats );
\r