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
4707 wb = b.bmWidthBytes;
\r
4709 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4710 int k = ((int*) pData)[i];
\r
4711 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4712 if(j >= 16) break;
\r
4714 if(j >= nrColors) nrColors = j+1;
\r
4716 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4718 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4719 for(w=0; w<(wb>>2); w+=2) {
\r
4720 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4721 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4722 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4723 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4724 pData[p++] = m | j<<4;
\r
4726 while(p&3) pData[p++] = 0;
\r
4729 wb = ((wb+31)>>5)<<2;
\r
4731 // write BITMAPFILEHEADER
\r
4732 fprintf(diagFile, "BM");
\r
4733 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4734 fputDW(diagFile, 0);
\r
4735 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4736 // write BITMAPINFOHEADER
\r
4737 fputDW(diagFile, 40);
\r
4738 fputDW(diagFile, b.bmWidth);
\r
4739 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4740 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4741 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 fputDW(diagFile, 0);
\r
4748 // write color table
\r
4750 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4751 // write bitmap data
\r
4752 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4753 fputc(pData[i], diagFile);
\r
4758 SelectObject(tmphdc, oldBitmap);
\r
4760 /* Massive cleanup */
\r
4761 for (x = 0; x < num_clips; x++)
\r
4762 DeleteObject(clips[x]);
\r
4765 DeleteObject(bufferBitmap);
\r
4768 ReleaseDC(hwndMain, hdc);
\r
4770 if (lastDrawnFlipView != flipView) {
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4774 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4777 /* CopyBoard(lastDrawn, board);*/
\r
4778 lastDrawnHighlight = highlightInfo;
\r
4779 lastDrawnPremove = premoveHighlightInfo;
\r
4780 lastDrawnFlipView = flipView;
\r
4781 lastDrawnValid = 1;
\r
4784 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4789 saveDiagFlag = 1; diagFile = f;
\r
4790 HDCDrawPosition(NULL, TRUE, NULL);
\r
4794 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4801 /*---------------------------------------------------------------------------*\
\r
4802 | CLIENT PAINT PROCEDURE
\r
4803 | This is the main event-handler for the WM_PAINT message.
\r
4805 \*---------------------------------------------------------------------------*/
\r
4807 PaintProc(HWND hwnd)
\r
4813 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4814 if (IsIconic(hwnd)) {
\r
4815 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4817 if (!appData.monoMode) {
\r
4818 SelectPalette(hdc, hPal, FALSE);
\r
4819 RealizePalette(hdc);
\r
4821 HDCDrawPosition(hdc, 1, NULL);
\r
4823 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4824 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4825 ETO_CLIPPED|ETO_OPAQUE,
\r
4826 &messageRect, messageText, strlen(messageText), NULL);
\r
4827 SelectObject(hdc, oldFont);
\r
4828 DisplayBothClocks();
\r
4830 EndPaint(hwnd,&ps);
\r
4838 * If the user selects on a border boundary, return -1; if off the board,
\r
4839 * return -2. Otherwise map the event coordinate to the square.
\r
4840 * The offset boardRect.left or boardRect.top must already have been
\r
4841 * subtracted from x.
\r
4844 EventToSquare(int x)
\r
4851 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4853 x /= (squareSize + lineGap);
\r
4854 if (x >= BOARD_SIZE)
\r
4865 DropEnable dropEnables[] = {
\r
4866 { 'P', DP_Pawn, "Pawn" },
\r
4867 { 'N', DP_Knight, "Knight" },
\r
4868 { 'B', DP_Bishop, "Bishop" },
\r
4869 { 'R', DP_Rook, "Rook" },
\r
4870 { 'Q', DP_Queen, "Queen" },
\r
4874 SetupDropMenu(HMENU hmenu)
\r
4876 int i, count, enable;
\r
4878 extern char white_holding[], black_holding[];
\r
4879 char item[MSG_SIZ];
\r
4881 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4882 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4883 dropEnables[i].piece);
\r
4885 while (p && *p++ == dropEnables[i].piece) count++;
\r
4886 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4887 enable = count > 0 || !appData.testLegality
\r
4888 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4889 && !appData.icsActive);
\r
4890 ModifyMenu(hmenu, dropEnables[i].command,
\r
4891 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4892 dropEnables[i].command, item);
\r
4896 /* Event handler for mouse messages */
\r
4898 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4902 static int recursive = 0;
\r
4904 // BOOLEAN needsRedraw = FALSE;
\r
4905 BOOLEAN saveAnimate;
\r
4906 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4907 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4908 ChessMove moveType;
\r
4911 if (message == WM_MBUTTONUP) {
\r
4912 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4913 to the middle button: we simulate pressing the left button too!
\r
4915 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4916 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4922 pt.x = LOWORD(lParam);
\r
4923 pt.y = HIWORD(lParam);
\r
4924 x = EventToSquare(pt.x - boardRect.left);
\r
4925 y = EventToSquare(pt.y - boardRect.top);
\r
4926 if (!flipView && y >= 0) {
\r
4927 y = BOARD_HEIGHT - 1 - y;
\r
4929 if (flipView && x >= 0) {
\r
4930 x = BOARD_WIDTH - 1 - x;
\r
4933 switch (message) {
\r
4934 case WM_LBUTTONDOWN:
\r
4935 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4936 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4937 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4938 if(gameInfo.holdingsWidth &&
\r
4939 (WhiteOnMove(currentMove)
\r
4940 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4941 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4942 // click in right holdings, for determining promotion piece
\r
4943 ChessSquare p = boards[currentMove][y][x];
\r
4944 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4945 if(p != EmptySquare) {
\r
4946 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4947 fromX = fromY = -1;
\r
4951 DrawPosition(FALSE, boards[currentMove]);
\r
4955 sameAgain = FALSE;
\r
4957 /* Downclick vertically off board; check if on clock */
\r
4958 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4959 if (gameMode == EditPosition) {
\r
4960 SetWhiteToPlayEvent();
\r
4961 } else if (gameMode == IcsPlayingBlack ||
\r
4962 gameMode == MachinePlaysWhite) {
\r
4964 } else if (gameMode == EditGame) {
\r
4965 AdjustClock(flipClock, -1);
\r
4967 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4968 if (gameMode == EditPosition) {
\r
4969 SetBlackToPlayEvent();
\r
4970 } else if (gameMode == IcsPlayingWhite ||
\r
4971 gameMode == MachinePlaysBlack) {
\r
4973 } else if (gameMode == EditGame) {
\r
4974 AdjustClock(!flipClock, -1);
\r
4977 if (!appData.highlightLastMove) {
\r
4978 ClearHighlights();
\r
4979 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4981 fromX = fromY = -1;
\r
4982 dragInfo.start.x = dragInfo.start.y = -1;
\r
4983 dragInfo.from = dragInfo.start;
\r
4985 } else if (x < 0 || y < 0
\r
4986 /* [HGM] block clicks between board and holdings */
\r
4987 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4988 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4989 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4990 /* EditPosition, empty square, or different color piece;
\r
4991 click-click move is possible */
\r
4994 } else if (fromX == x && fromY == y) {
\r
4995 /* Downclick on same square again */
\r
4996 ClearHighlights();
\r
4997 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4998 sameAgain = TRUE;
\r
4999 } else if (fromX != -1 &&
\r
5000 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5002 /* Downclick on different square. */
\r
5003 /* [HGM] if on holdings file, should count as new first click ! */
\r
5004 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5007 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5008 to make sure move is legal before showing promotion popup */
\r
5009 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5010 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5011 fromX = fromY = -1;
\r
5012 ClearHighlights();
\r
5013 DrawPosition(FALSE, boards[currentMove]);
\r
5016 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5017 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5018 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5019 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5020 appData.alwaysPromoteToQueen)) {
\r
5021 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5022 if (!appData.highlightLastMove) {
\r
5023 ClearHighlights();
\r
5024 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5027 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5028 SetHighlights(fromX, fromY, toX, toY);
\r
5029 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5030 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5031 If promotion to Q is legal, all are legal! */
\r
5032 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5033 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5034 // kludge to temporarily execute move on display, without promoting yet
\r
5035 promotionChoice = TRUE;
\r
5036 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5037 boards[currentMove][toY][toX] = p;
\r
5038 DrawPosition(FALSE, boards[currentMove]);
\r
5039 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5040 boards[currentMove][toY][toX] = q;
\r
5041 DisplayMessage("Select piece from holdings", "");
\r
5043 PromotionPopup(hwnd);
\r
5045 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5046 if (appData.animate || appData.highlightLastMove) {
\r
5047 SetHighlights(fromX, fromY, toX, toY);
\r
5049 ClearHighlights();
\r
5051 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5052 if (appData.animate && !appData.highlightLastMove) {
\r
5053 ClearHighlights();
\r
5054 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5057 fromX = fromY = -1;
\r
5061 if (gotPremove && moveType != Comment) {
\r
5062 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5063 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5064 } else ClearHighlights();
\r
5065 fromX = fromY = -1;
\r
5066 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5067 if(moveType != Comment) break;
\r
5069 /* First downclick, or restart on a square with same color piece */
\r
5070 if (!frozen && OKToStartUserMove(x, y)) {
\r
5073 dragInfo.lastpos = pt;
\r
5074 dragInfo.from.x = fromX;
\r
5075 dragInfo.from.y = fromY;
\r
5076 dragInfo.start = dragInfo.from;
\r
5077 SetCapture(hwndMain);
\r
5079 fromX = fromY = -1;
\r
5080 dragInfo.start.x = dragInfo.start.y = -1;
\r
5081 dragInfo.from = dragInfo.start;
\r
5082 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5086 case WM_LBUTTONUP:
\r
5088 if (fromX == -1) break;
\r
5089 if (x == fromX && y == fromY) {
\r
5090 dragInfo.from.x = dragInfo.from.y = -1;
\r
5091 /* Upclick on same square */
\r
5093 /* Clicked same square twice: abort click-click move */
\r
5094 fromX = fromY = -1;
\r
5096 ClearPremoveHighlights();
\r
5098 /* First square clicked: start click-click move */
\r
5099 SetHighlights(fromX, fromY, -1, -1);
\r
5101 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5102 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5103 /* Errant click; ignore */
\r
5106 /* Finish drag move. */
\r
5107 if (appData.debugMode) {
\r
5108 fprintf(debugFP, "release\n");
\r
5110 dragInfo.from.x = dragInfo.from.y = -1;
\r
5113 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5114 appData.animate = appData.animate && !appData.animateDragging;
\r
5115 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5116 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5117 fromX = fromY = -1;
\r
5118 ClearHighlights();
\r
5119 DrawPosition(FALSE, boards[currentMove]);
\r
5120 appData.animate = saveAnimate;
\r
5123 if(moveType != ImpossibleMove) {
\r
5124 /* [HGM] use move type to determine if move is promotion.
\r
5125 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5126 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5127 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5128 appData.alwaysPromoteToQueen))
\r
5129 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5131 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5132 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5133 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5134 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5135 // kludge to temporarily execute move on display, wthout promotng yet
\r
5136 promotionChoice = TRUE;
\r
5137 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5138 boards[currentMove][toY][toX] = p;
\r
5139 DrawPosition(FALSE, boards[currentMove]);
\r
5140 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5141 boards[currentMove][toY][toX] = q;
\r
5142 appData.animate = saveAnimate;
\r
5143 DisplayMessage("Select piece from holdings", "");
\r
5146 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5148 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5149 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5150 moveType == WhiteCapturesEnPassant ||
\r
5151 moveType == BlackCapturesEnPassant ) )
\r
5152 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5153 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5156 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5157 appData.animate = saveAnimate;
\r
5158 fromX = fromY = -1;
\r
5159 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5160 ClearHighlights();
\r
5162 if (appData.animate || appData.animateDragging ||
\r
5163 appData.highlightDragging || gotPremove) {
\r
5164 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5167 dragInfo.start.x = dragInfo.start.y = -1;
\r
5168 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5171 case WM_MOUSEMOVE:
\r
5172 if ((appData.animateDragging || appData.highlightDragging)
\r
5173 && (wParam & MK_LBUTTON)
\r
5174 && dragInfo.from.x >= 0)
\r
5176 BOOL full_repaint = FALSE;
\r
5178 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5179 if (appData.animateDragging) {
\r
5180 dragInfo.pos = pt;
\r
5182 if (appData.highlightDragging) {
\r
5183 SetHighlights(fromX, fromY, x, y);
\r
5184 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5185 full_repaint = TRUE;
\r
5189 DrawPosition( full_repaint, NULL);
\r
5191 dragInfo.lastpos = dragInfo.pos;
\r
5195 case WM_MOUSEWHEEL: // [DM]
\r
5196 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5197 /* Mouse Wheel is being rolled forward
\r
5198 * Play moves forward
\r
5200 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5201 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5202 /* Mouse Wheel is being rolled backward
\r
5203 * Play moves backward
\r
5205 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5206 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5210 case WM_MBUTTONDOWN:
\r
5211 case WM_RBUTTONDOWN:
\r
5214 fromX = fromY = -1;
\r
5215 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5216 dragInfo.start.x = dragInfo.start.y = -1;
\r
5217 dragInfo.from = dragInfo.start;
\r
5218 dragInfo.lastpos = dragInfo.pos;
\r
5219 if (appData.highlightDragging) {
\r
5220 ClearHighlights();
\r
5223 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5224 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5225 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5226 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5227 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5230 DrawPosition(TRUE, NULL);
\r
5232 switch (gameMode) {
\r
5233 case EditPosition:
\r
5234 case IcsExamining:
\r
5235 if (x < 0 || y < 0) break;
\r
5238 if (message == WM_MBUTTONDOWN) {
\r
5239 buttonCount = 3; /* even if system didn't think so */
\r
5240 if (wParam & MK_SHIFT)
\r
5241 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5243 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5244 } else { /* message == WM_RBUTTONDOWN */
\r
5245 /* Just have one menu, on the right button. Windows users don't
\r
5246 think to try the middle one, and sometimes other software steals
\r
5247 it, or it doesn't really exist. */
\r
5248 if(gameInfo.variant != VariantShogi)
\r
5249 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5251 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5254 case IcsPlayingWhite:
\r
5255 case IcsPlayingBlack:
\r
5257 case MachinePlaysWhite:
\r
5258 case MachinePlaysBlack:
\r
5259 if (appData.testLegality &&
\r
5260 gameInfo.variant != VariantBughouse &&
\r
5261 gameInfo.variant != VariantCrazyhouse) break;
\r
5262 if (x < 0 || y < 0) break;
\r
5265 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5266 SetupDropMenu(hmenu);
\r
5267 MenuPopup(hwnd, pt, hmenu, -1);
\r
5278 /* Preprocess messages for buttons in main window */
\r
5280 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5282 int id = GetWindowLong(hwnd, GWL_ID);
\r
5285 for (i=0; i<N_BUTTONS; i++) {
\r
5286 if (buttonDesc[i].id == id) break;
\r
5288 if (i == N_BUTTONS) return 0;
\r
5289 switch (message) {
\r
5294 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5295 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5302 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5305 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5306 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5307 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5308 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5310 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5312 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5313 PopUpMoveDialog((char)wParam);
\r
5319 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5322 /* Process messages for Promotion dialog box */
\r
5324 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5328 switch (message) {
\r
5329 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5330 /* Center the dialog over the application window */
\r
5331 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5332 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5333 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5334 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5335 SW_SHOW : SW_HIDE);
\r
5336 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5337 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5338 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5339 PieceToChar(WhiteAngel) != '~') ||
\r
5340 (PieceToChar(BlackAngel) >= 'A' &&
\r
5341 PieceToChar(BlackAngel) != '~') ) ?
\r
5342 SW_SHOW : SW_HIDE);
\r
5343 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5344 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5345 PieceToChar(WhiteMarshall) != '~') ||
\r
5346 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5347 PieceToChar(BlackMarshall) != '~') ) ?
\r
5348 SW_SHOW : SW_HIDE);
\r
5349 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5350 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5351 gameInfo.variant != VariantShogi ?
\r
5352 SW_SHOW : SW_HIDE);
\r
5353 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5354 gameInfo.variant != VariantShogi ?
\r
5355 SW_SHOW : SW_HIDE);
\r
5356 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5357 gameInfo.variant == VariantShogi ?
\r
5358 SW_SHOW : SW_HIDE);
\r
5359 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5360 gameInfo.variant == VariantShogi ?
\r
5361 SW_SHOW : SW_HIDE);
\r
5362 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5363 gameInfo.variant == VariantSuper ?
\r
5364 SW_SHOW : SW_HIDE);
\r
5367 case WM_COMMAND: /* message: received a command */
\r
5368 switch (LOWORD(wParam)) {
\r
5370 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5371 ClearHighlights();
\r
5372 DrawPosition(FALSE, NULL);
\r
5375 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5378 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5381 promoChar = PieceToChar(BlackRook);
\r
5384 promoChar = PieceToChar(BlackBishop);
\r
5386 case PB_Chancellor:
\r
5387 promoChar = PieceToChar(BlackMarshall);
\r
5389 case PB_Archbishop:
\r
5390 promoChar = PieceToChar(BlackAngel);
\r
5393 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5398 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5399 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5400 only show the popup when we are already sure the move is valid or
\r
5401 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5402 will figure out it is a promotion from the promoChar. */
\r
5403 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5404 if (!appData.highlightLastMove) {
\r
5405 ClearHighlights();
\r
5406 DrawPosition(FALSE, NULL);
\r
5413 /* Pop up promotion dialog */
\r
5415 PromotionPopup(HWND hwnd)
\r
5419 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5420 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5421 hwnd, (DLGPROC)lpProc);
\r
5422 FreeProcInstance(lpProc);
\r
5425 /* Toggle ShowThinking */
\r
5427 ToggleShowThinking()
\r
5429 appData.showThinking = !appData.showThinking;
\r
5430 ShowThinkingEvent();
\r
5434 LoadGameDialog(HWND hwnd, char* title)
\r
5438 char fileTitle[MSG_SIZ];
\r
5439 f = OpenFileDialog(hwnd, "rb", "",
\r
5440 appData.oldSaveStyle ? "gam" : "pgn",
\r
5442 title, &number, fileTitle, NULL);
\r
5444 cmailMsgLoaded = FALSE;
\r
5445 if (number == 0) {
\r
5446 int error = GameListBuild(f);
\r
5448 DisplayError("Cannot build game list", error);
\r
5449 } else if (!ListEmpty(&gameList) &&
\r
5450 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5451 GameListPopUp(f, fileTitle);
\r
5454 GameListDestroy();
\r
5457 LoadGame(f, number, fileTitle, FALSE);
\r
5462 ChangedConsoleFont()
\r
5465 CHARRANGE tmpsel, sel;
\r
5466 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5467 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5468 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5471 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5472 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5473 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5474 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5475 * size. This was undocumented in the version of MSVC++ that I had
\r
5476 * when I wrote the code, but is apparently documented now.
\r
5478 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5479 cfmt.bCharSet = f->lf.lfCharSet;
\r
5480 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5481 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5482 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5483 /* Why are the following seemingly needed too? */
\r
5484 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5485 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5486 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5488 tmpsel.cpMax = -1; /*999999?*/
\r
5489 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5490 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5491 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5492 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5494 paraf.cbSize = sizeof(paraf);
\r
5495 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5496 paraf.dxStartIndent = 0;
\r
5497 paraf.dxOffset = WRAP_INDENT;
\r
5498 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5499 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5502 /*---------------------------------------------------------------------------*\
\r
5504 * Window Proc for main window
\r
5506 \*---------------------------------------------------------------------------*/
\r
5508 /* Process messages for main window, etc. */
\r
5510 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5513 int wmId, wmEvent;
\r
5517 char fileTitle[MSG_SIZ];
\r
5518 char buf[MSG_SIZ];
\r
5519 static SnapData sd;
\r
5521 switch (message) {
\r
5523 case WM_PAINT: /* message: repaint portion of window */
\r
5527 case WM_ERASEBKGND:
\r
5528 if (IsIconic(hwnd)) {
\r
5529 /* Cheat; change the message */
\r
5530 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5532 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5536 case WM_LBUTTONDOWN:
\r
5537 case WM_MBUTTONDOWN:
\r
5538 case WM_RBUTTONDOWN:
\r
5539 case WM_LBUTTONUP:
\r
5540 case WM_MBUTTONUP:
\r
5541 case WM_RBUTTONUP:
\r
5542 case WM_MOUSEMOVE:
\r
5543 case WM_MOUSEWHEEL:
\r
5544 MouseEvent(hwnd, message, wParam, lParam);
\r
5547 JAWS_KB_NAVIGATION
\r
5551 JAWS_ALT_INTERCEPT
\r
5553 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5554 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5555 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5556 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5558 SendMessage(h, message, wParam, lParam);
\r
5559 } else if(lParam != KF_REPEAT) {
\r
5560 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5561 PopUpMoveDialog((char)wParam);
\r
5562 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5563 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5568 case WM_PALETTECHANGED:
\r
5569 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5571 HDC hdc = GetDC(hwndMain);
\r
5572 SelectPalette(hdc, hPal, TRUE);
\r
5573 nnew = RealizePalette(hdc);
\r
5575 paletteChanged = TRUE;
\r
5576 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5578 ReleaseDC(hwnd, hdc);
\r
5582 case WM_QUERYNEWPALETTE:
\r
5583 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5585 HDC hdc = GetDC(hwndMain);
\r
5586 paletteChanged = FALSE;
\r
5587 SelectPalette(hdc, hPal, FALSE);
\r
5588 nnew = RealizePalette(hdc);
\r
5590 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5592 ReleaseDC(hwnd, hdc);
\r
5597 case WM_COMMAND: /* message: command from application menu */
\r
5598 wmId = LOWORD(wParam);
\r
5599 wmEvent = HIWORD(wParam);
\r
5604 AnalysisPopDown();
\r
5605 SAY("new game enter a move to play against the computer with white");
\r
5608 case IDM_NewGameFRC:
\r
5609 if( NewGameFRC() == 0 ) {
\r
5611 AnalysisPopDown();
\r
5615 case IDM_NewVariant:
\r
5616 NewVariantPopup(hwnd);
\r
5619 case IDM_LoadGame:
\r
5620 LoadGameDialog(hwnd, "Load Game from File");
\r
5623 case IDM_LoadNextGame:
\r
5627 case IDM_LoadPrevGame:
\r
5631 case IDM_ReloadGame:
\r
5635 case IDM_LoadPosition:
\r
5636 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5637 Reset(FALSE, TRUE);
\r
5640 f = OpenFileDialog(hwnd, "rb", "",
\r
5641 appData.oldSaveStyle ? "pos" : "fen",
\r
5643 "Load Position from File", &number, fileTitle, NULL);
\r
5645 LoadPosition(f, number, fileTitle);
\r
5649 case IDM_LoadNextPosition:
\r
5650 ReloadPosition(1);
\r
5653 case IDM_LoadPrevPosition:
\r
5654 ReloadPosition(-1);
\r
5657 case IDM_ReloadPosition:
\r
5658 ReloadPosition(0);
\r
5661 case IDM_SaveGame:
\r
5662 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5663 f = OpenFileDialog(hwnd, "a", defName,
\r
5664 appData.oldSaveStyle ? "gam" : "pgn",
\r
5666 "Save Game to File", NULL, fileTitle, NULL);
\r
5668 SaveGame(f, 0, "");
\r
5672 case IDM_SavePosition:
\r
5673 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5674 f = OpenFileDialog(hwnd, "a", defName,
\r
5675 appData.oldSaveStyle ? "pos" : "fen",
\r
5677 "Save Position to File", NULL, fileTitle, NULL);
\r
5679 SavePosition(f, 0, "");
\r
5683 case IDM_SaveDiagram:
\r
5684 defName = "diagram";
\r
5685 f = OpenFileDialog(hwnd, "wb", defName,
\r
5688 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5694 case IDM_CopyGame:
\r
5695 CopyGameToClipboard();
\r
5698 case IDM_PasteGame:
\r
5699 PasteGameFromClipboard();
\r
5702 case IDM_CopyGameListToClipboard:
\r
5703 CopyGameListToClipboard();
\r
5706 /* [AS] Autodetect FEN or PGN data */
\r
5707 case IDM_PasteAny:
\r
5708 PasteGameOrFENFromClipboard();
\r
5711 /* [AS] Move history */
\r
5712 case IDM_ShowMoveHistory:
\r
5713 if( MoveHistoryIsUp() ) {
\r
5714 MoveHistoryPopDown();
\r
5717 MoveHistoryPopUp();
\r
5721 /* [AS] Eval graph */
\r
5722 case IDM_ShowEvalGraph:
\r
5723 if( EvalGraphIsUp() ) {
\r
5724 EvalGraphPopDown();
\r
5728 SetFocus(hwndMain);
\r
5732 /* [AS] Engine output */
\r
5733 case IDM_ShowEngineOutput:
\r
5734 if( EngineOutputIsUp() ) {
\r
5735 EngineOutputPopDown();
\r
5738 EngineOutputPopUp();
\r
5742 /* [AS] User adjudication */
\r
5743 case IDM_UserAdjudication_White:
\r
5744 UserAdjudicationEvent( +1 );
\r
5747 case IDM_UserAdjudication_Black:
\r
5748 UserAdjudicationEvent( -1 );
\r
5751 case IDM_UserAdjudication_Draw:
\r
5752 UserAdjudicationEvent( 0 );
\r
5755 /* [AS] Game list options dialog */
\r
5756 case IDM_GameListOptions:
\r
5757 GameListOptions();
\r
5764 case IDM_CopyPosition:
\r
5765 CopyFENToClipboard();
\r
5768 case IDM_PastePosition:
\r
5769 PasteFENFromClipboard();
\r
5772 case IDM_MailMove:
\r
5776 case IDM_ReloadCMailMsg:
\r
5777 Reset(TRUE, TRUE);
\r
5778 ReloadCmailMsgEvent(FALSE);
\r
5781 case IDM_Minimize:
\r
5782 ShowWindow(hwnd, SW_MINIMIZE);
\r
5789 case IDM_MachineWhite:
\r
5790 MachineWhiteEvent();
\r
5792 * refresh the tags dialog only if it's visible
\r
5794 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5796 tags = PGNTags(&gameInfo);
\r
5797 TagsPopUp(tags, CmailMsg());
\r
5800 SAY("computer starts playing white");
\r
5803 case IDM_MachineBlack:
\r
5804 MachineBlackEvent();
\r
5806 * refresh the tags dialog only if it's visible
\r
5808 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5810 tags = PGNTags(&gameInfo);
\r
5811 TagsPopUp(tags, CmailMsg());
\r
5814 SAY("computer starts playing black");
\r
5817 case IDM_TwoMachines:
\r
5818 TwoMachinesEvent();
\r
5820 * refresh the tags dialog only if it's visible
\r
5822 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5824 tags = PGNTags(&gameInfo);
\r
5825 TagsPopUp(tags, CmailMsg());
\r
5828 SAY("programs start playing each other");
\r
5831 case IDM_AnalysisMode:
\r
5832 if (!first.analysisSupport) {
\r
5833 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5834 DisplayError(buf, 0);
\r
5836 SAY("analyzing current position");
\r
5837 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5838 if (appData.icsActive) {
\r
5839 if (gameMode != IcsObserving) {
\r
5840 sprintf(buf, "You are not observing a game");
\r
5841 DisplayError(buf, 0);
\r
5842 /* secure check */
\r
5843 if (appData.icsEngineAnalyze) {
\r
5844 if (appData.debugMode)
\r
5845 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5846 ExitAnalyzeMode();
\r
5852 /* if enable, user want disable icsEngineAnalyze */
\r
5853 if (appData.icsEngineAnalyze) {
\r
5854 ExitAnalyzeMode();
\r
5858 appData.icsEngineAnalyze = TRUE;
\r
5859 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5862 if (!appData.showThinking) ToggleShowThinking();
\r
5863 AnalyzeModeEvent();
\r
5867 case IDM_AnalyzeFile:
\r
5868 if (!first.analysisSupport) {
\r
5869 char buf[MSG_SIZ];
\r
5870 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5871 DisplayError(buf, 0);
\r
5873 if (!appData.showThinking) ToggleShowThinking();
\r
5874 AnalyzeFileEvent();
\r
5875 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5876 AnalysisPeriodicEvent(1);
\r
5880 case IDM_IcsClient:
\r
5884 case IDM_EditGame:
\r
5889 case IDM_EditPosition:
\r
5890 EditPositionEvent();
\r
5891 SAY("to set up a position type a FEN");
\r
5894 case IDM_Training:
\r
5898 case IDM_ShowGameList:
\r
5899 ShowGameListProc();
\r
5902 case IDM_EditTags:
\r
5906 case IDM_EditComment:
\r
5907 if (commentDialogUp && editComment) {
\r
5910 EditCommentEvent();
\r
5930 case IDM_CallFlag:
\r
5950 case IDM_StopObserving:
\r
5951 StopObservingEvent();
\r
5954 case IDM_StopExamining:
\r
5955 StopExaminingEvent();
\r
5958 case IDM_TypeInMove:
\r
5959 PopUpMoveDialog('\000');
\r
5962 case IDM_TypeInName:
\r
5963 PopUpNameDialog('\000');
\r
5966 case IDM_Backward:
\r
5968 SetFocus(hwndMain);
\r
5975 SetFocus(hwndMain);
\r
5980 SetFocus(hwndMain);
\r
5985 SetFocus(hwndMain);
\r
5992 case IDM_TruncateGame:
\r
5993 TruncateGameEvent();
\r
6000 case IDM_RetractMove:
\r
6001 RetractMoveEvent();
\r
6004 case IDM_FlipView:
\r
6005 flipView = !flipView;
\r
6006 DrawPosition(FALSE, NULL);
\r
6009 case IDM_FlipClock:
\r
6010 flipClock = !flipClock;
\r
6011 DisplayBothClocks();
\r
6012 DrawPosition(FALSE, NULL);
\r
6015 case IDM_MuteSounds:
\r
6016 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6017 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6018 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6021 case IDM_GeneralOptions:
\r
6022 GeneralOptionsPopup(hwnd);
\r
6023 DrawPosition(TRUE, NULL);
\r
6026 case IDM_BoardOptions:
\r
6027 BoardOptionsPopup(hwnd);
\r
6030 case IDM_EnginePlayOptions:
\r
6031 EnginePlayOptionsPopup(hwnd);
\r
6034 case IDM_Engine1Options:
\r
6035 EngineOptionsPopup(hwnd, &first);
\r
6038 case IDM_Engine2Options:
\r
6039 EngineOptionsPopup(hwnd, &second);
\r
6042 case IDM_OptionsUCI:
\r
6043 UciOptionsPopup(hwnd);
\r
6046 case IDM_IcsOptions:
\r
6047 IcsOptionsPopup(hwnd);
\r
6051 FontsOptionsPopup(hwnd);
\r
6055 SoundOptionsPopup(hwnd);
\r
6058 case IDM_CommPort:
\r
6059 CommPortOptionsPopup(hwnd);
\r
6062 case IDM_LoadOptions:
\r
6063 LoadOptionsPopup(hwnd);
\r
6066 case IDM_SaveOptions:
\r
6067 SaveOptionsPopup(hwnd);
\r
6070 case IDM_TimeControl:
\r
6071 TimeControlOptionsPopup(hwnd);
\r
6074 case IDM_SaveSettings:
\r
6075 SaveSettings(settingsFileName);
\r
6078 case IDM_SaveSettingsOnExit:
\r
6079 saveSettingsOnExit = !saveSettingsOnExit;
\r
6080 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6081 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6082 MF_CHECKED : MF_UNCHECKED));
\r
6093 case IDM_AboutGame:
\r
6098 appData.debugMode = !appData.debugMode;
\r
6099 if (appData.debugMode) {
\r
6100 char dir[MSG_SIZ];
\r
6101 GetCurrentDirectory(MSG_SIZ, dir);
\r
6102 SetCurrentDirectory(installDir);
\r
6103 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6104 SetCurrentDirectory(dir);
\r
6105 setbuf(debugFP, NULL);
\r
6112 case IDM_HELPCONTENTS:
\r
6113 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6114 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6115 MessageBox (GetFocus(),
\r
6116 "Unable to activate help",
\r
6117 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6121 case IDM_HELPSEARCH:
\r
6122 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6123 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6124 MessageBox (GetFocus(),
\r
6125 "Unable to activate help",
\r
6126 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6130 case IDM_HELPHELP:
\r
6131 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6132 MessageBox (GetFocus(),
\r
6133 "Unable to activate help",
\r
6134 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6139 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6141 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6142 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6143 FreeProcInstance(lpProc);
\r
6146 case IDM_DirectCommand1:
\r
6147 AskQuestionEvent("Direct Command",
\r
6148 "Send to chess program:", "", "1");
\r
6150 case IDM_DirectCommand2:
\r
6151 AskQuestionEvent("Direct Command",
\r
6152 "Send to second chess program:", "", "2");
\r
6155 case EP_WhitePawn:
\r
6156 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6157 fromX = fromY = -1;
\r
6160 case EP_WhiteKnight:
\r
6161 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6162 fromX = fromY = -1;
\r
6165 case EP_WhiteBishop:
\r
6166 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6167 fromX = fromY = -1;
\r
6170 case EP_WhiteRook:
\r
6171 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6172 fromX = fromY = -1;
\r
6175 case EP_WhiteQueen:
\r
6176 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6177 fromX = fromY = -1;
\r
6180 case EP_WhiteFerz:
\r
6181 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6182 fromX = fromY = -1;
\r
6185 case EP_WhiteWazir:
\r
6186 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6187 fromX = fromY = -1;
\r
6190 case EP_WhiteAlfil:
\r
6191 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6192 fromX = fromY = -1;
\r
6195 case EP_WhiteCannon:
\r
6196 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6197 fromX = fromY = -1;
\r
6200 case EP_WhiteCardinal:
\r
6201 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6202 fromX = fromY = -1;
\r
6205 case EP_WhiteMarshall:
\r
6206 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6207 fromX = fromY = -1;
\r
6210 case EP_WhiteKing:
\r
6211 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6212 fromX = fromY = -1;
\r
6215 case EP_BlackPawn:
\r
6216 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6217 fromX = fromY = -1;
\r
6220 case EP_BlackKnight:
\r
6221 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6222 fromX = fromY = -1;
\r
6225 case EP_BlackBishop:
\r
6226 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6227 fromX = fromY = -1;
\r
6230 case EP_BlackRook:
\r
6231 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6232 fromX = fromY = -1;
\r
6235 case EP_BlackQueen:
\r
6236 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6237 fromX = fromY = -1;
\r
6240 case EP_BlackFerz:
\r
6241 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6242 fromX = fromY = -1;
\r
6245 case EP_BlackWazir:
\r
6246 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6247 fromX = fromY = -1;
\r
6250 case EP_BlackAlfil:
\r
6251 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6252 fromX = fromY = -1;
\r
6255 case EP_BlackCannon:
\r
6256 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6257 fromX = fromY = -1;
\r
6260 case EP_BlackCardinal:
\r
6261 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6262 fromX = fromY = -1;
\r
6265 case EP_BlackMarshall:
\r
6266 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6267 fromX = fromY = -1;
\r
6270 case EP_BlackKing:
\r
6271 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6272 fromX = fromY = -1;
\r
6275 case EP_EmptySquare:
\r
6276 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6277 fromX = fromY = -1;
\r
6280 case EP_ClearBoard:
\r
6281 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6282 fromX = fromY = -1;
\r
6286 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6287 fromX = fromY = -1;
\r
6291 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6292 fromX = fromY = -1;
\r
6296 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6297 fromX = fromY = -1;
\r
6301 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6302 fromX = fromY = -1;
\r
6306 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6307 fromX = fromY = -1;
\r
6311 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6312 fromX = fromY = -1;
\r
6316 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6317 fromX = fromY = -1;
\r
6321 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6322 fromX = fromY = -1;
\r
6326 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6327 fromX = fromY = -1;
\r
6331 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6337 case CLOCK_TIMER_ID:
\r
6338 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6339 clockTimerEvent = 0;
\r
6340 DecrementClocks(); /* call into back end */
\r
6342 case LOAD_GAME_TIMER_ID:
\r
6343 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6344 loadGameTimerEvent = 0;
\r
6345 AutoPlayGameLoop(); /* call into back end */
\r
6347 case ANALYSIS_TIMER_ID:
\r
6348 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6349 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6350 AnalysisPeriodicEvent(0);
\r
6352 KillTimer(hwnd, analysisTimerEvent);
\r
6353 analysisTimerEvent = 0;
\r
6356 case DELAYED_TIMER_ID:
\r
6357 KillTimer(hwnd, delayedTimerEvent);
\r
6358 delayedTimerEvent = 0;
\r
6359 delayedTimerCallback();
\r
6364 case WM_USER_Input:
\r
6365 InputEvent(hwnd, message, wParam, lParam);
\r
6368 /* [AS] Also move "attached" child windows */
\r
6369 case WM_WINDOWPOSCHANGING:
\r
6371 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6372 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6374 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6375 /* Window is moving */
\r
6378 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6379 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6380 rcMain.right = boardX + winWidth;
\r
6381 rcMain.top = boardY;
\r
6382 rcMain.bottom = boardY + winHeight;
\r
6384 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6385 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6386 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6387 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6388 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6395 /* [AS] Snapping */
\r
6396 case WM_ENTERSIZEMOVE:
\r
6397 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6398 if (hwnd == hwndMain) {
\r
6399 doingSizing = TRUE;
\r
6402 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6406 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6407 if (hwnd == hwndMain) {
\r
6408 lastSizing = wParam;
\r
6413 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6414 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6416 case WM_EXITSIZEMOVE:
\r
6417 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6418 if (hwnd == hwndMain) {
\r
6420 doingSizing = FALSE;
\r
6421 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6422 GetClientRect(hwnd, &client);
\r
6423 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6425 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6427 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6430 case WM_DESTROY: /* message: window being destroyed */
\r
6431 PostQuitMessage(0);
\r
6435 if (hwnd == hwndMain) {
\r
6440 default: /* Passes it on if unprocessed */
\r
6441 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6446 /*---------------------------------------------------------------------------*\
\r
6448 * Misc utility routines
\r
6450 \*---------------------------------------------------------------------------*/
\r
6453 * Decent random number generator, at least not as bad as Windows
\r
6454 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6456 unsigned int randstate;
\r
6461 randstate = randstate * 1664525 + 1013904223;
\r
6462 return (int) randstate & 0x7fffffff;
\r
6466 mysrandom(unsigned int seed)
\r
6473 * returns TRUE if user selects a different color, FALSE otherwise
\r
6477 ChangeColor(HWND hwnd, COLORREF *which)
\r
6479 static BOOL firstTime = TRUE;
\r
6480 static DWORD customColors[16];
\r
6482 COLORREF newcolor;
\r
6487 /* Make initial colors in use available as custom colors */
\r
6488 /* Should we put the compiled-in defaults here instead? */
\r
6490 customColors[i++] = lightSquareColor & 0xffffff;
\r
6491 customColors[i++] = darkSquareColor & 0xffffff;
\r
6492 customColors[i++] = whitePieceColor & 0xffffff;
\r
6493 customColors[i++] = blackPieceColor & 0xffffff;
\r
6494 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6495 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6497 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6498 customColors[i++] = textAttribs[ccl].color;
\r
6500 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6501 firstTime = FALSE;
\r
6504 cc.lStructSize = sizeof(cc);
\r
6505 cc.hwndOwner = hwnd;
\r
6506 cc.hInstance = NULL;
\r
6507 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6508 cc.lpCustColors = (LPDWORD) customColors;
\r
6509 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6511 if (!ChooseColor(&cc)) return FALSE;
\r
6513 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6514 if (newcolor == *which) return FALSE;
\r
6515 *which = newcolor;
\r
6519 InitDrawingColors();
\r
6520 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6525 MyLoadSound(MySound *ms)
\r
6531 if (ms->data) free(ms->data);
\r
6534 switch (ms->name[0]) {
\r
6540 /* System sound from Control Panel. Don't preload here. */
\r
6544 if (ms->name[1] == NULLCHAR) {
\r
6545 /* "!" alone = silence */
\r
6548 /* Builtin wave resource. Error if not found. */
\r
6549 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6550 if (h == NULL) break;
\r
6551 ms->data = (void *)LoadResource(hInst, h);
\r
6552 if (h == NULL) break;
\r
6557 /* .wav file. Error if not found. */
\r
6558 f = fopen(ms->name, "rb");
\r
6559 if (f == NULL) break;
\r
6560 if (fstat(fileno(f), &st) < 0) break;
\r
6561 ms->data = malloc(st.st_size);
\r
6562 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6568 char buf[MSG_SIZ];
\r
6569 sprintf(buf, "Error loading sound %s", ms->name);
\r
6570 DisplayError(buf, GetLastError());
\r
6576 MyPlaySound(MySound *ms)
\r
6578 BOOLEAN ok = FALSE;
\r
6580 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6581 switch (ms->name[0]) {
\r
6583 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6588 /* System sound from Control Panel (deprecated feature).
\r
6589 "$" alone or an unset sound name gets default beep (still in use). */
\r
6590 if (ms->name[1]) {
\r
6591 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6593 if (!ok) ok = MessageBeep(MB_OK);
\r
6596 /* Builtin wave resource, or "!" alone for silence */
\r
6597 if (ms->name[1]) {
\r
6598 if (ms->data == NULL) return FALSE;
\r
6599 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6605 /* .wav file. Error if not found. */
\r
6606 if (ms->data == NULL) return FALSE;
\r
6607 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6610 /* Don't print an error: this can happen innocently if the sound driver
\r
6611 is busy; for instance, if another instance of WinBoard is playing
\r
6612 a sound at about the same time. */
\r
6618 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6621 OPENFILENAME *ofn;
\r
6622 static UINT *number; /* gross that this is static */
\r
6624 switch (message) {
\r
6625 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6626 /* Center the dialog over the application window */
\r
6627 ofn = (OPENFILENAME *) lParam;
\r
6628 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6629 number = (UINT *) ofn->lCustData;
\r
6630 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6634 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6635 return FALSE; /* Allow for further processing */
\r
6638 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6639 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6641 return FALSE; /* Allow for further processing */
\r
6647 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6649 static UINT *number;
\r
6650 OPENFILENAME *ofname;
\r
6653 case WM_INITDIALOG:
\r
6654 ofname = (OPENFILENAME *)lParam;
\r
6655 number = (UINT *)(ofname->lCustData);
\r
6658 ofnot = (OFNOTIFY *)lParam;
\r
6659 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6660 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6669 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6670 char *nameFilt, char *dlgTitle, UINT *number,
\r
6671 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6673 OPENFILENAME openFileName;
\r
6674 char buf1[MSG_SIZ];
\r
6677 if (fileName == NULL) fileName = buf1;
\r
6678 if (defName == NULL) {
\r
6679 strcpy(fileName, "*.");
\r
6680 strcat(fileName, defExt);
\r
6682 strcpy(fileName, defName);
\r
6684 if (fileTitle) strcpy(fileTitle, "");
\r
6685 if (number) *number = 0;
\r
6687 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6688 openFileName.hwndOwner = hwnd;
\r
6689 openFileName.hInstance = (HANDLE) hInst;
\r
6690 openFileName.lpstrFilter = nameFilt;
\r
6691 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6692 openFileName.nMaxCustFilter = 0L;
\r
6693 openFileName.nFilterIndex = 1L;
\r
6694 openFileName.lpstrFile = fileName;
\r
6695 openFileName.nMaxFile = MSG_SIZ;
\r
6696 openFileName.lpstrFileTitle = fileTitle;
\r
6697 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6698 openFileName.lpstrInitialDir = NULL;
\r
6699 openFileName.lpstrTitle = dlgTitle;
\r
6700 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6701 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6702 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6703 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6704 openFileName.nFileOffset = 0;
\r
6705 openFileName.nFileExtension = 0;
\r
6706 openFileName.lpstrDefExt = defExt;
\r
6707 openFileName.lCustData = (LONG) number;
\r
6708 openFileName.lpfnHook = oldDialog ?
\r
6709 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6710 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6712 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6713 GetOpenFileName(&openFileName)) {
\r
6714 /* open the file */
\r
6715 f = fopen(openFileName.lpstrFile, write);
\r
6717 MessageBox(hwnd, "File open failed", NULL,
\r
6718 MB_OK|MB_ICONEXCLAMATION);
\r
6722 int err = CommDlgExtendedError();
\r
6723 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6732 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6734 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6737 * Get the first pop-up menu in the menu template. This is the
\r
6738 * menu that TrackPopupMenu displays.
\r
6740 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6742 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6745 * TrackPopup uses screen coordinates, so convert the
\r
6746 * coordinates of the mouse click to screen coordinates.
\r
6748 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6750 /* Draw and track the floating pop-up menu. */
\r
6751 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6752 pt.x, pt.y, 0, hwnd, NULL);
\r
6754 /* Destroy the menu.*/
\r
6755 DestroyMenu(hmenu);
\r
6760 int sizeX, sizeY, newSizeX, newSizeY;
\r
6762 } ResizeEditPlusButtonsClosure;
\r
6765 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6767 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6771 if (hChild == cl->hText) return TRUE;
\r
6772 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6773 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6774 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6775 ScreenToClient(cl->hDlg, &pt);
\r
6776 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6777 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6781 /* Resize a dialog that has a (rich) edit field filling most of
\r
6782 the top, with a row of buttons below */
\r
6784 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6787 int newTextHeight, newTextWidth;
\r
6788 ResizeEditPlusButtonsClosure cl;
\r
6790 /*if (IsIconic(hDlg)) return;*/
\r
6791 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6793 cl.hdwp = BeginDeferWindowPos(8);
\r
6795 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6796 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6797 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6798 if (newTextHeight < 0) {
\r
6799 newSizeY += -newTextHeight;
\r
6800 newTextHeight = 0;
\r
6802 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6803 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6809 cl.newSizeX = newSizeX;
\r
6810 cl.newSizeY = newSizeY;
\r
6811 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6813 EndDeferWindowPos(cl.hdwp);
\r
6816 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6818 RECT rChild, rParent;
\r
6819 int wChild, hChild, wParent, hParent;
\r
6820 int wScreen, hScreen, xNew, yNew;
\r
6823 /* Get the Height and Width of the child window */
\r
6824 GetWindowRect (hwndChild, &rChild);
\r
6825 wChild = rChild.right - rChild.left;
\r
6826 hChild = rChild.bottom - rChild.top;
\r
6828 /* Get the Height and Width of the parent window */
\r
6829 GetWindowRect (hwndParent, &rParent);
\r
6830 wParent = rParent.right - rParent.left;
\r
6831 hParent = rParent.bottom - rParent.top;
\r
6833 /* Get the display limits */
\r
6834 hdc = GetDC (hwndChild);
\r
6835 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6836 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6837 ReleaseDC(hwndChild, hdc);
\r
6839 /* Calculate new X position, then adjust for screen */
\r
6840 xNew = rParent.left + ((wParent - wChild) /2);
\r
6843 } else if ((xNew+wChild) > wScreen) {
\r
6844 xNew = wScreen - wChild;
\r
6847 /* Calculate new Y position, then adjust for screen */
\r
6849 yNew = rParent.top + ((hParent - hChild) /2);
\r
6852 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6857 } else if ((yNew+hChild) > hScreen) {
\r
6858 yNew = hScreen - hChild;
\r
6861 /* Set it, and return */
\r
6862 return SetWindowPos (hwndChild, NULL,
\r
6863 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6866 /* Center one window over another */
\r
6867 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6869 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6872 /*---------------------------------------------------------------------------*\
\r
6874 * Startup Dialog functions
\r
6876 \*---------------------------------------------------------------------------*/
\r
6878 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6880 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6882 while (*cd != NULL) {
\r
6883 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6889 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6891 char buf1[ARG_MAX];
\r
6894 if (str[0] == '@') {
\r
6895 FILE* f = fopen(str + 1, "r");
\r
6897 DisplayFatalError(str + 1, errno, 2);
\r
6900 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6902 buf1[len] = NULLCHAR;
\r
6906 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6909 char buf[MSG_SIZ];
\r
6910 char *end = strchr(str, '\n');
\r
6911 if (end == NULL) return;
\r
6912 memcpy(buf, str, end - str);
\r
6913 buf[end - str] = NULLCHAR;
\r
6914 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6920 SetStartupDialogEnables(HWND hDlg)
\r
6922 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6923 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6924 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6925 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6926 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6927 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6928 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6929 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6930 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6931 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6932 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6933 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6934 IsDlgButtonChecked(hDlg, OPT_View));
\r
6938 QuoteForFilename(char *filename)
\r
6940 int dquote, space;
\r
6941 dquote = strchr(filename, '"') != NULL;
\r
6942 space = strchr(filename, ' ') != NULL;
\r
6943 if (dquote || space) {
\r
6955 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6957 char buf[MSG_SIZ];
\r
6960 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6961 q = QuoteForFilename(nthcp);
\r
6962 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6963 if (*nthdir != NULLCHAR) {
\r
6964 q = QuoteForFilename(nthdir);
\r
6965 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6967 if (*nthcp == NULLCHAR) {
\r
6968 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6969 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6970 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6971 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6976 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6978 char buf[MSG_SIZ];
\r
6982 switch (message) {
\r
6983 case WM_INITDIALOG:
\r
6984 /* Center the dialog */
\r
6985 CenterWindow (hDlg, GetDesktopWindow());
\r
6986 /* Initialize the dialog items */
\r
6987 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6988 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6989 firstChessProgramNames);
\r
6990 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6991 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6992 secondChessProgramNames);
\r
6993 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6994 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6995 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6996 if (*appData.icsHelper != NULLCHAR) {
\r
6997 char *q = QuoteForFilename(appData.icsHelper);
\r
6998 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7000 if (*appData.icsHost == NULLCHAR) {
\r
7001 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7002 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7003 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7004 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7005 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7008 if (appData.icsActive) {
\r
7009 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7011 else if (appData.noChessProgram) {
\r
7012 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7015 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7018 SetStartupDialogEnables(hDlg);
\r
7022 switch (LOWORD(wParam)) {
\r
7024 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7025 strcpy(buf, "/fcp=");
\r
7026 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7028 ParseArgs(StringGet, &p);
\r
7029 strcpy(buf, "/scp=");
\r
7030 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7032 ParseArgs(StringGet, &p);
\r
7033 appData.noChessProgram = FALSE;
\r
7034 appData.icsActive = FALSE;
\r
7035 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7036 strcpy(buf, "/ics /icshost=");
\r
7037 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7039 ParseArgs(StringGet, &p);
\r
7040 if (appData.zippyPlay) {
\r
7041 strcpy(buf, "/fcp=");
\r
7042 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7044 ParseArgs(StringGet, &p);
\r
7046 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7047 appData.noChessProgram = TRUE;
\r
7048 appData.icsActive = FALSE;
\r
7050 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7051 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7054 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7055 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7057 ParseArgs(StringGet, &p);
\r
7059 EndDialog(hDlg, TRUE);
\r
7066 case IDM_HELPCONTENTS:
\r
7067 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7068 MessageBox (GetFocus(),
\r
7069 "Unable to activate help",
\r
7070 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7075 SetStartupDialogEnables(hDlg);
\r
7083 /*---------------------------------------------------------------------------*\
\r
7085 * About box dialog functions
\r
7087 \*---------------------------------------------------------------------------*/
\r
7089 /* Process messages for "About" dialog box */
\r
7091 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7093 switch (message) {
\r
7094 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7095 /* Center the dialog over the application window */
\r
7096 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7097 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7101 case WM_COMMAND: /* message: received a command */
\r
7102 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7103 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7104 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7112 /*---------------------------------------------------------------------------*\
\r
7114 * Comment Dialog functions
\r
7116 \*---------------------------------------------------------------------------*/
\r
7119 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7121 static HANDLE hwndText = NULL;
\r
7122 int len, newSizeX, newSizeY, flags;
\r
7123 static int sizeX, sizeY;
\r
7128 switch (message) {
\r
7129 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7130 /* Initialize the dialog items */
\r
7131 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7132 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7133 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7134 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7135 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7136 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7137 SetWindowText(hDlg, commentTitle);
\r
7138 if (editComment) {
\r
7139 SetFocus(hwndText);
\r
7141 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7143 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7144 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7145 MAKELPARAM(FALSE, 0));
\r
7146 /* Size and position the dialog */
\r
7147 if (!commentDialog) {
\r
7148 commentDialog = hDlg;
\r
7149 flags = SWP_NOZORDER;
\r
7150 GetClientRect(hDlg, &rect);
\r
7151 sizeX = rect.right;
\r
7152 sizeY = rect.bottom;
\r
7153 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7154 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7155 WINDOWPLACEMENT wp;
\r
7156 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7157 wp.length = sizeof(WINDOWPLACEMENT);
\r
7159 wp.showCmd = SW_SHOW;
\r
7160 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7161 wp.rcNormalPosition.left = commentX;
\r
7162 wp.rcNormalPosition.right = commentX + commentW;
\r
7163 wp.rcNormalPosition.top = commentY;
\r
7164 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7165 SetWindowPlacement(hDlg, &wp);
\r
7167 GetClientRect(hDlg, &rect);
\r
7168 newSizeX = rect.right;
\r
7169 newSizeY = rect.bottom;
\r
7170 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7171 newSizeX, newSizeY);
\r
7178 case WM_COMMAND: /* message: received a command */
\r
7179 switch (LOWORD(wParam)) {
\r
7181 if (editComment) {
\r
7183 /* Read changed options from the dialog box */
\r
7184 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7185 len = GetWindowTextLength(hwndText);
\r
7186 str = (char *) malloc(len + 1);
\r
7187 GetWindowText(hwndText, str, len + 1);
\r
7196 ReplaceComment(commentIndex, str);
\r
7203 case OPT_CancelComment:
\r
7207 case OPT_ClearComment:
\r
7208 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7211 case OPT_EditComment:
\r
7212 EditCommentEvent();
\r
7221 newSizeX = LOWORD(lParam);
\r
7222 newSizeY = HIWORD(lParam);
\r
7223 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7228 case WM_GETMINMAXINFO:
\r
7229 /* Prevent resizing window too small */
\r
7230 mmi = (MINMAXINFO *) lParam;
\r
7231 mmi->ptMinTrackSize.x = 100;
\r
7232 mmi->ptMinTrackSize.y = 100;
\r
7239 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7244 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7246 if (str == NULL) str = "";
\r
7247 p = (char *) malloc(2 * strlen(str) + 2);
\r
7250 if (*str == '\n') *q++ = '\r';
\r
7254 if (commentText != NULL) free(commentText);
\r
7256 commentIndex = index;
\r
7257 commentTitle = title;
\r
7259 editComment = edit;
\r
7261 if (commentDialog) {
\r
7262 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7263 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7265 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7266 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7267 hwndMain, (DLGPROC)lpProc);
\r
7268 FreeProcInstance(lpProc);
\r
7270 commentDialogUp = TRUE;
\r
7274 /*---------------------------------------------------------------------------*\
\r
7276 * Type-in move dialog functions
\r
7278 \*---------------------------------------------------------------------------*/
\r
7281 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7283 char move[MSG_SIZ];
\r
7285 ChessMove moveType;
\r
7286 int fromX, fromY, toX, toY;
\r
7289 switch (message) {
\r
7290 case WM_INITDIALOG:
\r
7291 move[0] = (char) lParam;
\r
7292 move[1] = NULLCHAR;
\r
7293 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7294 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7295 SetWindowText(hInput, move);
\r
7297 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7301 switch (LOWORD(wParam)) {
\r
7303 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7304 { int n; Board board;
\r
7306 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7307 EditPositionPasteFEN(move);
\r
7308 EndDialog(hDlg, TRUE);
\r
7311 // [HGM] movenum: allow move number to be typed in any mode
\r
7312 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7313 currentMove = 2*n-1;
\r
7314 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7315 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7316 EndDialog(hDlg, TRUE);
\r
7317 DrawPosition(TRUE, boards[currentMove]);
\r
7318 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7319 else DisplayMessage("", "");
\r
7323 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7324 gameMode != Training) {
\r
7325 DisplayMoveError("Displayed move is not current");
\r
7327 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7328 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7329 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7330 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7331 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7332 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7333 if (gameMode != Training)
\r
7334 forwardMostMove = currentMove;
\r
7335 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7337 DisplayMoveError("Could not parse move");
\r
7340 EndDialog(hDlg, TRUE);
\r
7343 EndDialog(hDlg, FALSE);
\r
7354 PopUpMoveDialog(char firstchar)
\r
7358 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7359 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7360 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7361 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7362 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7363 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7364 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7365 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7366 gameMode == Training) {
\r
7367 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7368 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7369 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7370 FreeProcInstance(lpProc);
\r
7374 /*---------------------------------------------------------------------------*\
\r
7376 * Type-in name dialog functions
\r
7378 \*---------------------------------------------------------------------------*/
\r
7381 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7383 char move[MSG_SIZ];
\r
7386 switch (message) {
\r
7387 case WM_INITDIALOG:
\r
7388 move[0] = (char) lParam;
\r
7389 move[1] = NULLCHAR;
\r
7390 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7391 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7392 SetWindowText(hInput, move);
\r
7394 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7398 switch (LOWORD(wParam)) {
\r
7400 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7401 appData.userName = strdup(move);
\r
7404 EndDialog(hDlg, TRUE);
\r
7407 EndDialog(hDlg, FALSE);
\r
7418 PopUpNameDialog(char firstchar)
\r
7422 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7423 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7424 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7425 FreeProcInstance(lpProc);
\r
7428 /*---------------------------------------------------------------------------*\
\r
7432 \*---------------------------------------------------------------------------*/
\r
7434 /* Nonmodal error box */
\r
7435 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7436 WPARAM wParam, LPARAM lParam);
\r
7439 ErrorPopUp(char *title, char *content)
\r
7443 BOOLEAN modal = hwndMain == NULL;
\r
7461 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7462 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7465 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7467 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7468 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7469 hwndMain, (DLGPROC)lpProc);
\r
7470 FreeProcInstance(lpProc);
\r
7477 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7478 if (errorDialog == NULL) return;
\r
7479 DestroyWindow(errorDialog);
\r
7480 errorDialog = NULL;
\r
7484 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7489 switch (message) {
\r
7490 case WM_INITDIALOG:
\r
7491 GetWindowRect(hDlg, &rChild);
\r
7494 SetWindowPos(hDlg, NULL, rChild.left,
\r
7495 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7496 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7500 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7501 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7502 and it doesn't work when you resize the dialog.
\r
7503 For now, just give it a default position.
\r
7505 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7507 errorDialog = hDlg;
\r
7508 SetWindowText(hDlg, errorTitle);
\r
7509 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7510 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7514 switch (LOWORD(wParam)) {
\r
7517 if (errorDialog == hDlg) errorDialog = NULL;
\r
7518 DestroyWindow(hDlg);
\r
7530 HWND gothicDialog = NULL;
\r
7533 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7537 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7539 switch (message) {
\r
7540 case WM_INITDIALOG:
\r
7541 GetWindowRect(hDlg, &rChild);
\r
7543 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7547 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7548 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7549 and it doesn't work when you resize the dialog.
\r
7550 For now, just give it a default position.
\r
7552 gothicDialog = hDlg;
\r
7553 SetWindowText(hDlg, errorTitle);
\r
7554 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7555 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7559 switch (LOWORD(wParam)) {
\r
7562 if (errorDialog == hDlg) errorDialog = NULL;
\r
7563 DestroyWindow(hDlg);
\r
7575 GothicPopUp(char *title, VariantClass variant)
\r
7578 static char *lastTitle;
\r
7580 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7581 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7583 if(lastTitle != title && gothicDialog != NULL) {
\r
7584 DestroyWindow(gothicDialog);
\r
7585 gothicDialog = NULL;
\r
7587 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7588 title = lastTitle;
\r
7589 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7590 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7591 hwndMain, (DLGPROC)lpProc);
\r
7592 FreeProcInstance(lpProc);
\r
7597 /*---------------------------------------------------------------------------*\
\r
7599 * Ics Interaction console functions
\r
7601 \*---------------------------------------------------------------------------*/
\r
7603 #define HISTORY_SIZE 64
\r
7604 static char *history[HISTORY_SIZE];
\r
7605 int histIn = 0, histP = 0;
\r
7608 SaveInHistory(char *cmd)
\r
7610 if (history[histIn] != NULL) {
\r
7611 free(history[histIn]);
\r
7612 history[histIn] = NULL;
\r
7614 if (*cmd == NULLCHAR) return;
\r
7615 history[histIn] = StrSave(cmd);
\r
7616 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7617 if (history[histIn] != NULL) {
\r
7618 free(history[histIn]);
\r
7619 history[histIn] = NULL;
\r
7625 PrevInHistory(char *cmd)
\r
7628 if (histP == histIn) {
\r
7629 if (history[histIn] != NULL) free(history[histIn]);
\r
7630 history[histIn] = StrSave(cmd);
\r
7632 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7633 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7635 return history[histP];
\r
7641 if (histP == histIn) return NULL;
\r
7642 histP = (histP + 1) % HISTORY_SIZE;
\r
7643 return history[histP];
\r
7650 BOOLEAN immediate;
\r
7651 } IcsTextMenuEntry;
\r
7652 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7653 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7656 ParseIcsTextMenu(char *icsTextMenuString)
\r
7659 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7660 char *p = icsTextMenuString;
\r
7661 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7664 if (e->command != NULL) {
\r
7666 e->command = NULL;
\r
7670 e = icsTextMenuEntry;
\r
7671 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7672 if (*p == ';' || *p == '\n') {
\r
7673 e->item = strdup("-");
\r
7674 e->command = NULL;
\r
7676 } else if (*p == '-') {
\r
7677 e->item = strdup("-");
\r
7678 e->command = NULL;
\r
7682 char *q, *r, *s, *t;
\r
7684 q = strchr(p, ',');
\r
7685 if (q == NULL) break;
\r
7687 r = strchr(q + 1, ',');
\r
7688 if (r == NULL) break;
\r
7690 s = strchr(r + 1, ',');
\r
7691 if (s == NULL) break;
\r
7694 t = strchr(s + 1, c);
\r
7697 t = strchr(s + 1, c);
\r
7699 if (t != NULL) *t = NULLCHAR;
\r
7700 e->item = strdup(p);
\r
7701 e->command = strdup(q + 1);
\r
7702 e->getname = *(r + 1) != '0';
\r
7703 e->immediate = *(s + 1) != '0';
\r
7707 if (t == NULL) break;
\r
7716 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7720 hmenu = LoadMenu(hInst, "TextMenu");
\r
7721 h = GetSubMenu(hmenu, 0);
\r
7723 if (strcmp(e->item, "-") == 0) {
\r
7724 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7726 if (e->item[0] == '|') {
\r
7727 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7728 IDM_CommandX + i, &e->item[1]);
\r
7730 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7739 WNDPROC consoleTextWindowProc;
\r
7742 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7744 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7745 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7749 SetWindowText(hInput, command);
\r
7751 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7753 sel.cpMin = 999999;
\r
7754 sel.cpMax = 999999;
\r
7755 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7760 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7761 if (sel.cpMin == sel.cpMax) {
\r
7762 /* Expand to surrounding word */
\r
7765 tr.chrg.cpMax = sel.cpMin;
\r
7766 tr.chrg.cpMin = --sel.cpMin;
\r
7767 if (sel.cpMin < 0) break;
\r
7768 tr.lpstrText = name;
\r
7769 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7770 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7774 tr.chrg.cpMin = sel.cpMax;
\r
7775 tr.chrg.cpMax = ++sel.cpMax;
\r
7776 tr.lpstrText = name;
\r
7777 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7778 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7781 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7782 MessageBeep(MB_ICONEXCLAMATION);
\r
7786 tr.lpstrText = name;
\r
7787 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7789 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7790 MessageBeep(MB_ICONEXCLAMATION);
\r
7793 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7796 sprintf(buf, "%s %s", command, name);
\r
7797 SetWindowText(hInput, buf);
\r
7798 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7800 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7801 SetWindowText(hInput, buf);
\r
7802 sel.cpMin = 999999;
\r
7803 sel.cpMax = 999999;
\r
7804 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7810 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7815 switch (message) {
\r
7817 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7820 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7823 sel.cpMin = 999999;
\r
7824 sel.cpMax = 999999;
\r
7825 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7826 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7831 if(wParam != '\022') {
\r
7832 if (wParam == '\t') {
\r
7833 if (GetKeyState(VK_SHIFT) < 0) {
\r
7835 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7836 if (buttonDesc[0].hwnd) {
\r
7837 SetFocus(buttonDesc[0].hwnd);
\r
7839 SetFocus(hwndMain);
\r
7843 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7846 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7847 JAWS_DELETE( SetFocus(hInput); )
\r
7848 SendMessage(hInput, message, wParam, lParam);
\r
7851 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7852 case WM_RBUTTONUP:
\r
7853 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7854 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7855 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7858 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7859 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7860 if (sel.cpMin == sel.cpMax) {
\r
7861 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7862 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7864 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7865 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7867 pt.x = LOWORD(lParam);
\r
7868 pt.y = HIWORD(lParam);
\r
7869 MenuPopup(hwnd, pt, hmenu, -1);
\r
7873 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7875 return SendMessage(hInput, message, wParam, lParam);
\r
7876 case WM_MBUTTONDOWN:
\r
7877 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7878 case WM_RBUTTONDOWN:
\r
7879 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7880 /* Move selection here if it was empty */
\r
7882 pt.x = LOWORD(lParam);
\r
7883 pt.y = HIWORD(lParam);
\r
7884 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7885 if (sel.cpMin == sel.cpMax) {
\r
7886 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7887 sel.cpMax = sel.cpMin;
\r
7888 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7890 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7894 switch (LOWORD(wParam)) {
\r
7895 case IDM_QuickPaste:
\r
7897 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7898 if (sel.cpMin == sel.cpMax) {
\r
7899 MessageBeep(MB_ICONEXCLAMATION);
\r
7902 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7903 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7904 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7909 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7912 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7915 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7919 int i = LOWORD(wParam) - IDM_CommandX;
\r
7920 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7921 icsTextMenuEntry[i].command != NULL) {
\r
7922 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7923 icsTextMenuEntry[i].getname,
\r
7924 icsTextMenuEntry[i].immediate);
\r
7932 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7935 WNDPROC consoleInputWindowProc;
\r
7938 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7940 char buf[MSG_SIZ];
\r
7942 static BOOL sendNextChar = FALSE;
\r
7943 static BOOL quoteNextChar = FALSE;
\r
7944 InputSource *is = consoleInputSource;
\r
7948 switch (message) {
\r
7950 if (!appData.localLineEditing || sendNextChar) {
\r
7951 is->buf[0] = (CHAR) wParam;
\r
7953 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7954 sendNextChar = FALSE;
\r
7957 if (quoteNextChar) {
\r
7958 buf[0] = (char) wParam;
\r
7959 buf[1] = NULLCHAR;
\r
7960 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7961 quoteNextChar = FALSE;
\r
7965 case '\r': /* Enter key */
\r
7966 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7967 if (consoleEcho) SaveInHistory(is->buf);
\r
7968 is->buf[is->count++] = '\n';
\r
7969 is->buf[is->count] = NULLCHAR;
\r
7970 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7971 if (consoleEcho) {
\r
7972 ConsoleOutput(is->buf, is->count, TRUE);
\r
7973 } else if (appData.localLineEditing) {
\r
7974 ConsoleOutput("\n", 1, TRUE);
\r
7977 case '\033': /* Escape key */
\r
7978 SetWindowText(hwnd, "");
\r
7979 cf.cbSize = sizeof(CHARFORMAT);
\r
7980 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7981 if (consoleEcho) {
\r
7982 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7984 cf.crTextColor = COLOR_ECHOOFF;
\r
7986 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7987 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7989 case '\t': /* Tab key */
\r
7990 if (GetKeyState(VK_SHIFT) < 0) {
\r
7992 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7995 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7996 if (buttonDesc[0].hwnd) {
\r
7997 SetFocus(buttonDesc[0].hwnd);
\r
7999 SetFocus(hwndMain);
\r
8003 case '\023': /* Ctrl+S */
\r
8004 sendNextChar = TRUE;
\r
8006 case '\021': /* Ctrl+Q */
\r
8007 quoteNextChar = TRUE;
\r
8017 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8018 p = PrevInHistory(buf);
\r
8020 SetWindowText(hwnd, p);
\r
8021 sel.cpMin = 999999;
\r
8022 sel.cpMax = 999999;
\r
8023 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8028 p = NextInHistory();
\r
8030 SetWindowText(hwnd, p);
\r
8031 sel.cpMin = 999999;
\r
8032 sel.cpMax = 999999;
\r
8033 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8039 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8043 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8047 case WM_MBUTTONDOWN:
\r
8048 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8049 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8051 case WM_RBUTTONUP:
\r
8052 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8053 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8054 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8058 hmenu = LoadMenu(hInst, "InputMenu");
\r
8059 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8060 if (sel.cpMin == sel.cpMax) {
\r
8061 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8062 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8064 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8065 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8067 pt.x = LOWORD(lParam);
\r
8068 pt.y = HIWORD(lParam);
\r
8069 MenuPopup(hwnd, pt, hmenu, -1);
\r
8073 switch (LOWORD(wParam)) {
\r
8075 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8077 case IDM_SelectAll:
\r
8079 sel.cpMax = -1; /*999999?*/
\r
8080 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8083 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8086 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8089 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8094 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8097 #define CO_MAX 100000
\r
8098 #define CO_TRIM 1000
\r
8101 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8103 static SnapData sd;
\r
8104 static HWND hText, hInput /*, hFocus*/;
\r
8105 // InputSource *is = consoleInputSource;
\r
8107 static int sizeX, sizeY;
\r
8108 int newSizeX, newSizeY;
\r
8111 switch (message) {
\r
8113 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8115 ENLINK *pLink = (ENLINK*)lParam;
\r
8116 if (pLink->msg == WM_LBUTTONUP)
\r
8120 tr.chrg = pLink->chrg;
\r
8121 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8122 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8123 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8124 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8125 free(tr.lpstrText);
\r
8129 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8130 hwndConsole = hDlg;
\r
8131 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8132 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8134 consoleTextWindowProc = (WNDPROC)
\r
8135 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8136 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8137 consoleInputWindowProc = (WNDPROC)
\r
8138 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8139 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8140 Colorize(ColorNormal, TRUE);
\r
8141 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8142 ChangedConsoleFont();
\r
8143 GetClientRect(hDlg, &rect);
\r
8144 sizeX = rect.right;
\r
8145 sizeY = rect.bottom;
\r
8146 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8147 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8148 WINDOWPLACEMENT wp;
\r
8149 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8150 wp.length = sizeof(WINDOWPLACEMENT);
\r
8152 wp.showCmd = SW_SHOW;
\r
8153 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8154 wp.rcNormalPosition.left = wpConsole.x;
\r
8155 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8156 wp.rcNormalPosition.top = wpConsole.y;
\r
8157 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8158 SetWindowPlacement(hDlg, &wp);
\r
8161 // [HGM] Chessknight's change 2004-07-13
\r
8162 else { /* Determine Defaults */
\r
8163 WINDOWPLACEMENT wp;
\r
8164 wpConsole.x = winWidth + 1;
\r
8165 wpConsole.y = boardY;
\r
8166 wpConsole.width = screenWidth - winWidth;
\r
8167 wpConsole.height = winHeight;
\r
8168 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8169 wp.length = sizeof(WINDOWPLACEMENT);
\r
8171 wp.showCmd = SW_SHOW;
\r
8172 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8173 wp.rcNormalPosition.left = wpConsole.x;
\r
8174 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8175 wp.rcNormalPosition.top = wpConsole.y;
\r
8176 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8177 SetWindowPlacement(hDlg, &wp);
\r
8192 if (IsIconic(hDlg)) break;
\r
8193 newSizeX = LOWORD(lParam);
\r
8194 newSizeY = HIWORD(lParam);
\r
8195 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8196 RECT rectText, rectInput;
\r
8198 int newTextHeight, newTextWidth;
\r
8199 GetWindowRect(hText, &rectText);
\r
8200 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8201 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8202 if (newTextHeight < 0) {
\r
8203 newSizeY += -newTextHeight;
\r
8204 newTextHeight = 0;
\r
8206 SetWindowPos(hText, NULL, 0, 0,
\r
8207 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8208 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8209 pt.x = rectInput.left;
\r
8210 pt.y = rectInput.top + newSizeY - sizeY;
\r
8211 ScreenToClient(hDlg, &pt);
\r
8212 SetWindowPos(hInput, NULL,
\r
8213 pt.x, pt.y, /* needs client coords */
\r
8214 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8215 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8221 case WM_GETMINMAXINFO:
\r
8222 /* Prevent resizing window too small */
\r
8223 mmi = (MINMAXINFO *) lParam;
\r
8224 mmi->ptMinTrackSize.x = 100;
\r
8225 mmi->ptMinTrackSize.y = 100;
\r
8228 /* [AS] Snapping */
\r
8229 case WM_ENTERSIZEMOVE:
\r
8230 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8233 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8236 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8238 case WM_EXITSIZEMOVE:
\r
8239 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8242 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8249 HWND hCons, hText;
\r
8251 if (hwndConsole) return;
\r
8252 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8253 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8256 // make the text item in the console do URL links
\r
8257 hText = GetDlgItem(hCons, OPT_ConsoleText);
\r
8258 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8259 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8260 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8265 ConsoleOutput(char* data, int length, int forceVisible)
\r
8270 char buf[CO_MAX+1];
\r
8273 static int delayLF = 0;
\r
8274 CHARRANGE savesel, sel;
\r
8276 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8284 while (length--) {
\r
8292 } else if (*p == '\007') {
\r
8293 MyPlaySound(&sounds[(int)SoundBell]);
\r
8300 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8301 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8302 /* Save current selection */
\r
8303 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8304 exlen = GetWindowTextLength(hText);
\r
8305 /* Find out whether current end of text is visible */
\r
8306 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8307 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8308 /* Trim existing text if it's too long */
\r
8309 if (exlen + (q - buf) > CO_MAX) {
\r
8310 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8313 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8314 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8316 savesel.cpMin -= trim;
\r
8317 savesel.cpMax -= trim;
\r
8318 if (exlen < 0) exlen = 0;
\r
8319 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8320 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8322 /* Append the new text */
\r
8323 sel.cpMin = exlen;
\r
8324 sel.cpMax = exlen;
\r
8325 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8326 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8327 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8328 if (forceVisible || exlen == 0 ||
\r
8329 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8330 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8331 /* Scroll to make new end of text visible if old end of text
\r
8332 was visible or new text is an echo of user typein */
\r
8333 sel.cpMin = 9999999;
\r
8334 sel.cpMax = 9999999;
\r
8335 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8336 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8337 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8338 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8340 if (savesel.cpMax == exlen || forceVisible) {
\r
8341 /* Move insert point to new end of text if it was at the old
\r
8342 end of text or if the new text is an echo of user typein */
\r
8343 sel.cpMin = 9999999;
\r
8344 sel.cpMax = 9999999;
\r
8345 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8347 /* Restore previous selection */
\r
8348 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8350 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8357 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8361 COLORREF oldFg, oldBg;
\r
8365 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8367 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8368 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8369 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8372 rect.right = x + squareSize;
\r
8374 rect.bottom = y + squareSize;
\r
8377 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8378 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8379 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8380 &rect, str, strlen(str), NULL);
\r
8382 (void) SetTextColor(hdc, oldFg);
\r
8383 (void) SetBkColor(hdc, oldBg);
\r
8384 (void) SelectObject(hdc, oldFont);
\r
8388 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8389 RECT *rect, char *color, char *flagFell)
\r
8393 COLORREF oldFg, oldBg;
\r
8396 if (appData.clockMode) {
\r
8398 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8400 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8407 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8408 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8410 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8411 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8413 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8417 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8418 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8419 rect, str, strlen(str), NULL);
\r
8420 if(logoHeight > 0 && appData.clockMode) {
\r
8422 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8423 r.top = rect->top + logoHeight/2;
\r
8424 r.left = rect->left;
\r
8425 r.right = rect->right;
\r
8426 r.bottom = rect->bottom;
\r
8427 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8428 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8429 &r, str, strlen(str), NULL);
\r
8431 (void) SetTextColor(hdc, oldFg);
\r
8432 (void) SetBkColor(hdc, oldBg);
\r
8433 (void) SelectObject(hdc, oldFont);
\r
8438 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8444 if( count <= 0 ) {
\r
8445 if (appData.debugMode) {
\r
8446 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8449 return ERROR_INVALID_USER_BUFFER;
\r
8452 ResetEvent(ovl->hEvent);
\r
8453 ovl->Offset = ovl->OffsetHigh = 0;
\r
8454 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8458 err = GetLastError();
\r
8459 if (err == ERROR_IO_PENDING) {
\r
8460 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8464 err = GetLastError();
\r
8471 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8476 ResetEvent(ovl->hEvent);
\r
8477 ovl->Offset = ovl->OffsetHigh = 0;
\r
8478 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8482 err = GetLastError();
\r
8483 if (err == ERROR_IO_PENDING) {
\r
8484 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8488 err = GetLastError();
\r
8494 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8495 void CheckForInputBufferFull( InputSource * is )
\r
8497 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8498 /* Look for end of line */
\r
8499 char * p = is->buf;
\r
8501 while( p < is->next && *p != '\n' ) {
\r
8505 if( p >= is->next ) {
\r
8506 if (appData.debugMode) {
\r
8507 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8510 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8511 is->count = (DWORD) -1;
\r
8512 is->next = is->buf;
\r
8518 InputThread(LPVOID arg)
\r
8523 is = (InputSource *) arg;
\r
8524 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8525 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8526 while (is->hThread != NULL) {
\r
8527 is->error = DoReadFile(is->hFile, is->next,
\r
8528 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8529 &is->count, &ovl);
\r
8530 if (is->error == NO_ERROR) {
\r
8531 is->next += is->count;
\r
8533 if (is->error == ERROR_BROKEN_PIPE) {
\r
8534 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8537 is->count = (DWORD) -1;
\r
8538 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8543 CheckForInputBufferFull( is );
\r
8545 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8547 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8549 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8552 CloseHandle(ovl.hEvent);
\r
8553 CloseHandle(is->hFile);
\r
8555 if (appData.debugMode) {
\r
8556 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8563 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8565 NonOvlInputThread(LPVOID arg)
\r
8572 is = (InputSource *) arg;
\r
8573 while (is->hThread != NULL) {
\r
8574 is->error = ReadFile(is->hFile, is->next,
\r
8575 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8576 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8577 if (is->error == NO_ERROR) {
\r
8578 /* Change CRLF to LF */
\r
8579 if (is->next > is->buf) {
\r
8581 i = is->count + 1;
\r
8589 if (prev == '\r' && *p == '\n') {
\r
8601 if (is->error == ERROR_BROKEN_PIPE) {
\r
8602 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8605 is->count = (DWORD) -1;
\r
8609 CheckForInputBufferFull( is );
\r
8611 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8613 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8615 if (is->count < 0) break; /* Quit on error */
\r
8617 CloseHandle(is->hFile);
\r
8622 SocketInputThread(LPVOID arg)
\r
8626 is = (InputSource *) arg;
\r
8627 while (is->hThread != NULL) {
\r
8628 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8629 if ((int)is->count == SOCKET_ERROR) {
\r
8630 is->count = (DWORD) -1;
\r
8631 is->error = WSAGetLastError();
\r
8633 is->error = NO_ERROR;
\r
8634 is->next += is->count;
\r
8635 if (is->count == 0 && is->second == is) {
\r
8636 /* End of file on stderr; quit with no message */
\r
8640 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8642 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8644 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8650 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8654 is = (InputSource *) lParam;
\r
8655 if (is->lineByLine) {
\r
8656 /* Feed in lines one by one */
\r
8657 char *p = is->buf;
\r
8659 while (q < is->next) {
\r
8660 if (*q++ == '\n') {
\r
8661 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8666 /* Move any partial line to the start of the buffer */
\r
8668 while (p < is->next) {
\r
8673 if (is->error != NO_ERROR || is->count == 0) {
\r
8674 /* Notify backend of the error. Note: If there was a partial
\r
8675 line at the end, it is not flushed through. */
\r
8676 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8679 /* Feed in the whole chunk of input at once */
\r
8680 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8681 is->next = is->buf;
\r
8685 /*---------------------------------------------------------------------------*\
\r
8687 * Menu enables. Used when setting various modes.
\r
8689 \*---------------------------------------------------------------------------*/
\r
8697 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8699 while (enab->item > 0) {
\r
8700 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8705 Enables gnuEnables[] = {
\r
8706 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8707 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8708 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8709 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8710 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8711 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8712 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8713 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8714 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8715 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8719 Enables icsEnables[] = {
\r
8720 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8721 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8722 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8723 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8724 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8725 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8726 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8727 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8728 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8729 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8730 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8731 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8736 Enables zippyEnables[] = {
\r
8737 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8738 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8739 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8744 Enables ncpEnables[] = {
\r
8745 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8746 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8747 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8748 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8754 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8763 Enables trainingOnEnables[] = {
\r
8764 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8765 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8766 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8767 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8768 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8769 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8770 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8771 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8775 Enables trainingOffEnables[] = {
\r
8776 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8777 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8778 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8779 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8780 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8781 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8782 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8783 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8787 /* These modify either ncpEnables or gnuEnables */
\r
8788 Enables cmailEnables[] = {
\r
8789 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8790 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8791 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8792 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8794 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8799 Enables machineThinkingEnables[] = {
\r
8800 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8818 Enables userThinkingEnables[] = {
\r
8819 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8820 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8821 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8822 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8823 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8824 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8825 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8826 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8827 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8828 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8829 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8830 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8831 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8832 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8833 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8837 /*---------------------------------------------------------------------------*\
\r
8839 * Front-end interface functions exported by XBoard.
\r
8840 * Functions appear in same order as prototypes in frontend.h.
\r
8842 \*---------------------------------------------------------------------------*/
\r
8846 static UINT prevChecked = 0;
\r
8847 static int prevPausing = 0;
\r
8850 if (pausing != prevPausing) {
\r
8851 prevPausing = pausing;
\r
8852 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8853 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8854 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8857 switch (gameMode) {
\r
8858 case BeginningOfGame:
\r
8859 if (appData.icsActive)
\r
8860 nowChecked = IDM_IcsClient;
\r
8861 else if (appData.noChessProgram)
\r
8862 nowChecked = IDM_EditGame;
\r
8864 nowChecked = IDM_MachineBlack;
\r
8866 case MachinePlaysBlack:
\r
8867 nowChecked = IDM_MachineBlack;
\r
8869 case MachinePlaysWhite:
\r
8870 nowChecked = IDM_MachineWhite;
\r
8872 case TwoMachinesPlay:
\r
8873 nowChecked = IDM_TwoMachines;
\r
8876 nowChecked = IDM_AnalysisMode;
\r
8879 nowChecked = IDM_AnalyzeFile;
\r
8882 nowChecked = IDM_EditGame;
\r
8884 case PlayFromGameFile:
\r
8885 nowChecked = IDM_LoadGame;
\r
8887 case EditPosition:
\r
8888 nowChecked = IDM_EditPosition;
\r
8891 nowChecked = IDM_Training;
\r
8893 case IcsPlayingWhite:
\r
8894 case IcsPlayingBlack:
\r
8895 case IcsObserving:
\r
8897 nowChecked = IDM_IcsClient;
\r
8904 if (prevChecked != 0)
\r
8905 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8906 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8907 if (nowChecked != 0)
\r
8908 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8909 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8911 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8912 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8913 MF_BYCOMMAND|MF_ENABLED);
\r
8915 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8916 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8919 prevChecked = nowChecked;
\r
8921 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8922 if (appData.icsActive) {
\r
8923 if (appData.icsEngineAnalyze) {
\r
8924 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8925 MF_BYCOMMAND|MF_CHECKED);
\r
8927 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8928 MF_BYCOMMAND|MF_UNCHECKED);
\r
8936 HMENU hmenu = GetMenu(hwndMain);
\r
8937 SetMenuEnables(hmenu, icsEnables);
\r
8938 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8939 MF_BYPOSITION|MF_ENABLED);
\r
8941 if (appData.zippyPlay) {
\r
8942 SetMenuEnables(hmenu, zippyEnables);
\r
8943 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8944 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8945 MF_BYCOMMAND|MF_ENABLED);
\r
8953 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8959 HMENU hmenu = GetMenu(hwndMain);
\r
8960 SetMenuEnables(hmenu, ncpEnables);
\r
8961 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8962 MF_BYPOSITION|MF_GRAYED);
\r
8963 DrawMenuBar(hwndMain);
\r
8969 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8973 SetTrainingModeOn()
\r
8976 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8977 for (i = 0; i < N_BUTTONS; i++) {
\r
8978 if (buttonDesc[i].hwnd != NULL)
\r
8979 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8984 VOID SetTrainingModeOff()
\r
8987 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8988 for (i = 0; i < N_BUTTONS; i++) {
\r
8989 if (buttonDesc[i].hwnd != NULL)
\r
8990 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8996 SetUserThinkingEnables()
\r
8998 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9002 SetMachineThinkingEnables()
\r
9004 HMENU hMenu = GetMenu(hwndMain);
\r
9005 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9007 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9009 if (gameMode == MachinePlaysBlack) {
\r
9010 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9011 } else if (gameMode == MachinePlaysWhite) {
\r
9012 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9013 } else if (gameMode == TwoMachinesPlay) {
\r
9014 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9020 DisplayTitle(char *str)
\r
9022 char title[MSG_SIZ], *host;
\r
9023 if (str[0] != NULLCHAR) {
\r
9024 strcpy(title, str);
\r
9025 } else if (appData.icsActive) {
\r
9026 if (appData.icsCommPort[0] != NULLCHAR)
\r
9029 host = appData.icsHost;
\r
9030 sprintf(title, "%s: %s", szTitle, host);
\r
9031 } else if (appData.noChessProgram) {
\r
9032 strcpy(title, szTitle);
\r
9034 strcpy(title, szTitle);
\r
9035 strcat(title, ": ");
\r
9036 strcat(title, first.tidy);
\r
9038 SetWindowText(hwndMain, title);
\r
9043 DisplayMessage(char *str1, char *str2)
\r
9047 int remain = MESSAGE_TEXT_MAX - 1;
\r
9050 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9051 messageText[0] = NULLCHAR;
\r
9053 len = strlen(str1);
\r
9054 if (len > remain) len = remain;
\r
9055 strncpy(messageText, str1, len);
\r
9056 messageText[len] = NULLCHAR;
\r
9059 if (*str2 && remain >= 2) {
\r
9061 strcat(messageText, " ");
\r
9064 len = strlen(str2);
\r
9065 if (len > remain) len = remain;
\r
9066 strncat(messageText, str2, len);
\r
9068 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9070 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9074 hdc = GetDC(hwndMain);
\r
9075 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9076 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9077 &messageRect, messageText, strlen(messageText), NULL);
\r
9078 (void) SelectObject(hdc, oldFont);
\r
9079 (void) ReleaseDC(hwndMain, hdc);
\r
9083 DisplayError(char *str, int error)
\r
9085 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9091 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9092 NULL, error, LANG_NEUTRAL,
\r
9093 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9095 sprintf(buf, "%s:\n%s", str, buf2);
\r
9097 ErrorMap *em = errmap;
\r
9098 while (em->err != 0 && em->err != error) em++;
\r
9099 if (em->err != 0) {
\r
9100 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9102 sprintf(buf, "%s:\nError code %d", str, error);
\r
9107 ErrorPopUp("Error", buf);
\r
9112 DisplayMoveError(char *str)
\r
9114 fromX = fromY = -1;
\r
9115 ClearHighlights();
\r
9116 DrawPosition(FALSE, NULL);
\r
9117 if (appData.popupMoveErrors) {
\r
9118 ErrorPopUp("Error", str);
\r
9120 DisplayMessage(str, "");
\r
9121 moveErrorMessageUp = TRUE;
\r
9126 DisplayFatalError(char *str, int error, int exitStatus)
\r
9128 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9130 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9133 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9134 NULL, error, LANG_NEUTRAL,
\r
9135 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9137 sprintf(buf, "%s:\n%s", str, buf2);
\r
9139 ErrorMap *em = errmap;
\r
9140 while (em->err != 0 && em->err != error) em++;
\r
9141 if (em->err != 0) {
\r
9142 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9144 sprintf(buf, "%s:\nError code %d", str, error);
\r
9149 if (appData.debugMode) {
\r
9150 fprintf(debugFP, "%s: %s\n", label, str);
\r
9152 if (appData.popupExitMessage) {
\r
9153 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9154 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9156 ExitEvent(exitStatus);
\r
9161 DisplayInformation(char *str)
\r
9163 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9168 DisplayNote(char *str)
\r
9170 ErrorPopUp("Note", str);
\r
9175 char *title, *question, *replyPrefix;
\r
9180 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9182 static QuestionParams *qp;
\r
9183 char reply[MSG_SIZ];
\r
9186 switch (message) {
\r
9187 case WM_INITDIALOG:
\r
9188 qp = (QuestionParams *) lParam;
\r
9189 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9190 SetWindowText(hDlg, qp->title);
\r
9191 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9192 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9196 switch (LOWORD(wParam)) {
\r
9198 strcpy(reply, qp->replyPrefix);
\r
9199 if (*reply) strcat(reply, " ");
\r
9200 len = strlen(reply);
\r
9201 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9202 strcat(reply, "\n");
\r
9203 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9204 EndDialog(hDlg, TRUE);
\r
9205 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9208 EndDialog(hDlg, FALSE);
\r
9219 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9221 QuestionParams qp;
\r
9225 qp.question = question;
\r
9226 qp.replyPrefix = replyPrefix;
\r
9228 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9229 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9230 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9231 FreeProcInstance(lpProc);
\r
9234 /* [AS] Pick FRC position */
\r
9235 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9237 static int * lpIndexFRC;
\r
9243 case WM_INITDIALOG:
\r
9244 lpIndexFRC = (int *) lParam;
\r
9246 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9248 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9249 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9250 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9251 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9256 switch( LOWORD(wParam) ) {
\r
9258 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9259 EndDialog( hDlg, 0 );
\r
9260 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9263 EndDialog( hDlg, 1 );
\r
9265 case IDC_NFG_Edit:
\r
9266 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9267 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9269 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9272 case IDC_NFG_Random:
\r
9273 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9274 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9287 int index = appData.defaultFrcPosition;
\r
9288 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9290 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9292 if( result == 0 ) {
\r
9293 appData.defaultFrcPosition = index;
\r
9299 /* [AS] Game list options */
\r
9305 static GLT_Item GLT_ItemInfo[] = {
\r
9306 { GLT_EVENT, "Event" },
\r
9307 { GLT_SITE, "Site" },
\r
9308 { GLT_DATE, "Date" },
\r
9309 { GLT_ROUND, "Round" },
\r
9310 { GLT_PLAYERS, "Players" },
\r
9311 { GLT_RESULT, "Result" },
\r
9312 { GLT_WHITE_ELO, "White Rating" },
\r
9313 { GLT_BLACK_ELO, "Black Rating" },
\r
9314 { GLT_TIME_CONTROL,"Time Control" },
\r
9315 { GLT_VARIANT, "Variant" },
\r
9316 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9317 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9321 const char * GLT_FindItem( char id )
\r
9323 const char * result = 0;
\r
9325 GLT_Item * list = GLT_ItemInfo;
\r
9327 while( list->id != 0 ) {
\r
9328 if( list->id == id ) {
\r
9329 result = list->name;
\r
9339 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9341 const char * name = GLT_FindItem( id );
\r
9344 if( index >= 0 ) {
\r
9345 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9348 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9353 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9357 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9360 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9364 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9366 pc = GLT_ALL_TAGS;
\r
9369 if( strchr( tags, *pc ) == 0 ) {
\r
9370 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9375 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9378 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9380 char result = '\0';
\r
9383 GLT_Item * list = GLT_ItemInfo;
\r
9385 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9386 while( list->id != 0 ) {
\r
9387 if( strcmp( list->name, name ) == 0 ) {
\r
9388 result = list->id;
\r
9399 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9401 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9402 int idx2 = idx1 + delta;
\r
9403 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9405 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9408 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9409 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9410 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9411 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9415 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9417 static char glt[64];
\r
9418 static char * lpUserGLT;
\r
9422 case WM_INITDIALOG:
\r
9423 lpUserGLT = (char *) lParam;
\r
9425 strcpy( glt, lpUserGLT );
\r
9427 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9429 /* Initialize list */
\r
9430 GLT_TagsToList( hDlg, glt );
\r
9432 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9437 switch( LOWORD(wParam) ) {
\r
9440 char * pc = lpUserGLT;
\r
9442 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9446 id = GLT_ListItemToTag( hDlg, idx );
\r
9450 } while( id != '\0' );
\r
9452 EndDialog( hDlg, 0 );
\r
9455 EndDialog( hDlg, 1 );
\r
9458 case IDC_GLT_Default:
\r
9459 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9460 GLT_TagsToList( hDlg, glt );
\r
9463 case IDC_GLT_Restore:
\r
9464 strcpy( glt, lpUserGLT );
\r
9465 GLT_TagsToList( hDlg, glt );
\r
9469 GLT_MoveSelection( hDlg, -1 );
\r
9472 case IDC_GLT_Down:
\r
9473 GLT_MoveSelection( hDlg, +1 );
\r
9483 int GameListOptions()
\r
9487 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9489 strcpy( glt, appData.gameListTags );
\r
9491 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9493 if( result == 0 ) {
\r
9494 /* [AS] Memory leak here! */
\r
9495 appData.gameListTags = strdup( glt );
\r
9503 DisplayIcsInteractionTitle(char *str)
\r
9505 char consoleTitle[MSG_SIZ];
\r
9507 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9508 SetWindowText(hwndConsole, consoleTitle);
\r
9512 DrawPosition(int fullRedraw, Board board)
\r
9514 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9521 fromX = fromY = -1;
\r
9522 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9523 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9524 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9525 dragInfo.lastpos = dragInfo.pos;
\r
9526 dragInfo.start.x = dragInfo.start.y = -1;
\r
9527 dragInfo.from = dragInfo.start;
\r
9529 DrawPosition(TRUE, NULL);
\r
9535 CommentPopUp(char *title, char *str)
\r
9537 HWND hwnd = GetActiveWindow();
\r
9538 EitherCommentPopUp(0, title, str, FALSE);
\r
9540 SetActiveWindow(hwnd);
\r
9544 CommentPopDown(void)
\r
9546 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9547 if (commentDialog) {
\r
9548 ShowWindow(commentDialog, SW_HIDE);
\r
9550 commentDialogUp = FALSE;
\r
9554 EditCommentPopUp(int index, char *title, char *str)
\r
9556 EitherCommentPopUp(index, title, str, TRUE);
\r
9563 MyPlaySound(&sounds[(int)SoundMove]);
\r
9566 VOID PlayIcsWinSound()
\r
9568 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9571 VOID PlayIcsLossSound()
\r
9573 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9576 VOID PlayIcsDrawSound()
\r
9578 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9581 VOID PlayIcsUnfinishedSound()
\r
9583 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9589 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9597 consoleEcho = TRUE;
\r
9598 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9599 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9600 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9609 consoleEcho = FALSE;
\r
9610 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9611 /* This works OK: set text and background both to the same color */
\r
9613 cf.crTextColor = COLOR_ECHOOFF;
\r
9614 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9615 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9618 /* No Raw()...? */
\r
9620 void Colorize(ColorClass cc, int continuation)
\r
9622 currentColorClass = cc;
\r
9623 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9624 consoleCF.crTextColor = textAttribs[cc].color;
\r
9625 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9626 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9632 static char buf[MSG_SIZ];
\r
9633 DWORD bufsiz = MSG_SIZ;
\r
9635 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9636 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9638 if (!GetUserName(buf, &bufsiz)) {
\r
9639 /*DisplayError("Error getting user name", GetLastError());*/
\r
9640 strcpy(buf, "User");
\r
9648 static char buf[MSG_SIZ];
\r
9649 DWORD bufsiz = MSG_SIZ;
\r
9651 if (!GetComputerName(buf, &bufsiz)) {
\r
9652 /*DisplayError("Error getting host name", GetLastError());*/
\r
9653 strcpy(buf, "Unknown");
\r
9660 ClockTimerRunning()
\r
9662 return clockTimerEvent != 0;
\r
9668 if (clockTimerEvent == 0) return FALSE;
\r
9669 KillTimer(hwndMain, clockTimerEvent);
\r
9670 clockTimerEvent = 0;
\r
9675 StartClockTimer(long millisec)
\r
9677 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9678 (UINT) millisec, NULL);
\r
9682 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9685 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9687 if(appData.noGUI) return;
\r
9688 hdc = GetDC(hwndMain);
\r
9689 if (!IsIconic(hwndMain)) {
\r
9690 DisplayAClock(hdc, timeRemaining, highlight,
\r
9691 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9693 if (highlight && iconCurrent == iconBlack) {
\r
9694 iconCurrent = iconWhite;
\r
9695 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9696 if (IsIconic(hwndMain)) {
\r
9697 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9700 (void) ReleaseDC(hwndMain, hdc);
\r
9702 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9706 DisplayBlackClock(long timeRemaining, int highlight)
\r
9709 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9711 if(appData.noGUI) return;
\r
9712 hdc = GetDC(hwndMain);
\r
9713 if (!IsIconic(hwndMain)) {
\r
9714 DisplayAClock(hdc, timeRemaining, highlight,
\r
9715 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9717 if (highlight && iconCurrent == iconWhite) {
\r
9718 iconCurrent = iconBlack;
\r
9719 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9720 if (IsIconic(hwndMain)) {
\r
9721 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9724 (void) ReleaseDC(hwndMain, hdc);
\r
9726 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9731 LoadGameTimerRunning()
\r
9733 return loadGameTimerEvent != 0;
\r
9737 StopLoadGameTimer()
\r
9739 if (loadGameTimerEvent == 0) return FALSE;
\r
9740 KillTimer(hwndMain, loadGameTimerEvent);
\r
9741 loadGameTimerEvent = 0;
\r
9746 StartLoadGameTimer(long millisec)
\r
9748 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9749 (UINT) millisec, NULL);
\r
9757 char fileTitle[MSG_SIZ];
\r
9759 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9760 f = OpenFileDialog(hwndMain, "a", defName,
\r
9761 appData.oldSaveStyle ? "gam" : "pgn",
\r
9763 "Save Game to File", NULL, fileTitle, NULL);
\r
9765 SaveGame(f, 0, "");
\r
9772 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9774 if (delayedTimerEvent != 0) {
\r
9775 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9776 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9778 KillTimer(hwndMain, delayedTimerEvent);
\r
9779 delayedTimerEvent = 0;
\r
9780 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9781 delayedTimerCallback();
\r
9783 delayedTimerCallback = cb;
\r
9784 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9785 (UINT) millisec, NULL);
\r
9788 DelayedEventCallback
\r
9791 if (delayedTimerEvent) {
\r
9792 return delayedTimerCallback;
\r
9799 CancelDelayedEvent()
\r
9801 if (delayedTimerEvent) {
\r
9802 KillTimer(hwndMain, delayedTimerEvent);
\r
9803 delayedTimerEvent = 0;
\r
9807 DWORD GetWin32Priority(int nice)
\r
9808 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9810 REALTIME_PRIORITY_CLASS 0x00000100
\r
9811 HIGH_PRIORITY_CLASS 0x00000080
\r
9812 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9813 NORMAL_PRIORITY_CLASS 0x00000020
\r
9814 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9815 IDLE_PRIORITY_CLASS 0x00000040
\r
9817 if (nice < -15) return 0x00000080;
\r
9818 if (nice < 0) return 0x00008000;
\r
9819 if (nice == 0) return 0x00000020;
\r
9820 if (nice < 15) return 0x00004000;
\r
9821 return 0x00000040;
\r
9824 /* Start a child process running the given program.
\r
9825 The process's standard output can be read from "from", and its
\r
9826 standard input can be written to "to".
\r
9827 Exit with fatal error if anything goes wrong.
\r
9828 Returns an opaque pointer that can be used to destroy the process
\r
9832 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9834 #define BUFSIZE 4096
\r
9836 HANDLE hChildStdinRd, hChildStdinWr,
\r
9837 hChildStdoutRd, hChildStdoutWr;
\r
9838 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9839 SECURITY_ATTRIBUTES saAttr;
\r
9841 PROCESS_INFORMATION piProcInfo;
\r
9842 STARTUPINFO siStartInfo;
\r
9844 char buf[MSG_SIZ];
\r
9847 if (appData.debugMode) {
\r
9848 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9853 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9854 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9855 saAttr.bInheritHandle = TRUE;
\r
9856 saAttr.lpSecurityDescriptor = NULL;
\r
9859 * The steps for redirecting child's STDOUT:
\r
9860 * 1. Create anonymous pipe to be STDOUT for child.
\r
9861 * 2. Create a noninheritable duplicate of read handle,
\r
9862 * and close the inheritable read handle.
\r
9865 /* Create a pipe for the child's STDOUT. */
\r
9866 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9867 return GetLastError();
\r
9870 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9871 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9872 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9873 FALSE, /* not inherited */
\r
9874 DUPLICATE_SAME_ACCESS);
\r
9876 return GetLastError();
\r
9878 CloseHandle(hChildStdoutRd);
\r
9881 * The steps for redirecting child's STDIN:
\r
9882 * 1. Create anonymous pipe to be STDIN for child.
\r
9883 * 2. Create a noninheritable duplicate of write handle,
\r
9884 * and close the inheritable write handle.
\r
9887 /* Create a pipe for the child's STDIN. */
\r
9888 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9889 return GetLastError();
\r
9892 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9893 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9894 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9895 FALSE, /* not inherited */
\r
9896 DUPLICATE_SAME_ACCESS);
\r
9898 return GetLastError();
\r
9900 CloseHandle(hChildStdinWr);
\r
9902 /* Arrange to (1) look in dir for the child .exe file, and
\r
9903 * (2) have dir be the child's working directory. Interpret
\r
9904 * dir relative to the directory WinBoard loaded from. */
\r
9905 GetCurrentDirectory(MSG_SIZ, buf);
\r
9906 SetCurrentDirectory(installDir);
\r
9907 SetCurrentDirectory(dir);
\r
9909 /* Now create the child process. */
\r
9911 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9912 siStartInfo.lpReserved = NULL;
\r
9913 siStartInfo.lpDesktop = NULL;
\r
9914 siStartInfo.lpTitle = NULL;
\r
9915 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9916 siStartInfo.cbReserved2 = 0;
\r
9917 siStartInfo.lpReserved2 = NULL;
\r
9918 siStartInfo.hStdInput = hChildStdinRd;
\r
9919 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9920 siStartInfo.hStdError = hChildStdoutWr;
\r
9922 fSuccess = CreateProcess(NULL,
\r
9923 cmdLine, /* command line */
\r
9924 NULL, /* process security attributes */
\r
9925 NULL, /* primary thread security attrs */
\r
9926 TRUE, /* handles are inherited */
\r
9927 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9928 NULL, /* use parent's environment */
\r
9930 &siStartInfo, /* STARTUPINFO pointer */
\r
9931 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9933 err = GetLastError();
\r
9934 SetCurrentDirectory(buf); /* return to prev directory */
\r
9939 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9940 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9941 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9944 /* Close the handles we don't need in the parent */
\r
9945 CloseHandle(piProcInfo.hThread);
\r
9946 CloseHandle(hChildStdinRd);
\r
9947 CloseHandle(hChildStdoutWr);
\r
9949 /* Prepare return value */
\r
9950 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9951 cp->kind = CPReal;
\r
9952 cp->hProcess = piProcInfo.hProcess;
\r
9953 cp->pid = piProcInfo.dwProcessId;
\r
9954 cp->hFrom = hChildStdoutRdDup;
\r
9955 cp->hTo = hChildStdinWrDup;
\r
9957 *pr = (void *) cp;
\r
9959 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9960 2000 where engines sometimes don't see the initial command(s)
\r
9961 from WinBoard and hang. I don't understand how that can happen,
\r
9962 but the Sleep is harmless, so I've put it in. Others have also
\r
9963 reported what may be the same problem, so hopefully this will fix
\r
9964 it for them too. */
\r
9972 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9974 ChildProc *cp; int result;
\r
9976 cp = (ChildProc *) pr;
\r
9977 if (cp == NULL) return;
\r
9979 switch (cp->kind) {
\r
9981 /* TerminateProcess is considered harmful, so... */
\r
9982 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9983 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9984 /* The following doesn't work because the chess program
\r
9985 doesn't "have the same console" as WinBoard. Maybe
\r
9986 we could arrange for this even though neither WinBoard
\r
9987 nor the chess program uses a console for stdio? */
\r
9988 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9990 /* [AS] Special termination modes for misbehaving programs... */
\r
9991 if( signal == 9 ) {
\r
9992 result = TerminateProcess( cp->hProcess, 0 );
\r
9994 if ( appData.debugMode) {
\r
9995 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9998 else if( signal == 10 ) {
\r
9999 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10001 if( dw != WAIT_OBJECT_0 ) {
\r
10002 result = TerminateProcess( cp->hProcess, 0 );
\r
10004 if ( appData.debugMode) {
\r
10005 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10011 CloseHandle(cp->hProcess);
\r
10015 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10019 closesocket(cp->sock);
\r
10024 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10025 closesocket(cp->sock);
\r
10026 closesocket(cp->sock2);
\r
10034 InterruptChildProcess(ProcRef pr)
\r
10038 cp = (ChildProc *) pr;
\r
10039 if (cp == NULL) return;
\r
10040 switch (cp->kind) {
\r
10042 /* The following doesn't work because the chess program
\r
10043 doesn't "have the same console" as WinBoard. Maybe
\r
10044 we could arrange for this even though neither WinBoard
\r
10045 nor the chess program uses a console for stdio */
\r
10046 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10051 /* Can't interrupt */
\r
10055 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10062 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10064 char cmdLine[MSG_SIZ];
\r
10066 if (port[0] == NULLCHAR) {
\r
10067 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10069 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10071 return StartChildProcess(cmdLine, "", pr);
\r
10075 /* Code to open TCP sockets */
\r
10078 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10083 struct sockaddr_in sa, mysa;
\r
10084 struct hostent FAR *hp;
\r
10085 unsigned short uport;
\r
10086 WORD wVersionRequested;
\r
10089 /* Initialize socket DLL */
\r
10090 wVersionRequested = MAKEWORD(1, 1);
\r
10091 err = WSAStartup(wVersionRequested, &wsaData);
\r
10092 if (err != 0) return err;
\r
10094 /* Make socket */
\r
10095 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10096 err = WSAGetLastError();
\r
10101 /* Bind local address using (mostly) don't-care values.
\r
10103 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10104 mysa.sin_family = AF_INET;
\r
10105 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10106 uport = (unsigned short) 0;
\r
10107 mysa.sin_port = htons(uport);
\r
10108 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10109 == SOCKET_ERROR) {
\r
10110 err = WSAGetLastError();
\r
10115 /* Resolve remote host name */
\r
10116 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10117 if (!(hp = gethostbyname(host))) {
\r
10118 unsigned int b0, b1, b2, b3;
\r
10120 err = WSAGetLastError();
\r
10122 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10123 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10124 hp->h_addrtype = AF_INET;
\r
10125 hp->h_length = 4;
\r
10126 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10127 hp->h_addr_list[0] = (char *) malloc(4);
\r
10128 hp->h_addr_list[0][0] = (char) b0;
\r
10129 hp->h_addr_list[0][1] = (char) b1;
\r
10130 hp->h_addr_list[0][2] = (char) b2;
\r
10131 hp->h_addr_list[0][3] = (char) b3;
\r
10137 sa.sin_family = hp->h_addrtype;
\r
10138 uport = (unsigned short) atoi(port);
\r
10139 sa.sin_port = htons(uport);
\r
10140 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10142 /* Make connection */
\r
10143 if (connect(s, (struct sockaddr *) &sa,
\r
10144 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10145 err = WSAGetLastError();
\r
10150 /* Prepare return value */
\r
10151 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10152 cp->kind = CPSock;
\r
10154 *pr = (ProcRef *) cp;
\r
10160 OpenCommPort(char *name, ProcRef *pr)
\r
10165 char fullname[MSG_SIZ];
\r
10167 if (*name != '\\')
\r
10168 sprintf(fullname, "\\\\.\\%s", name);
\r
10170 strcpy(fullname, name);
\r
10172 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10173 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10174 if (h == (HANDLE) -1) {
\r
10175 return GetLastError();
\r
10179 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10181 /* Accumulate characters until a 100ms pause, then parse */
\r
10182 ct.ReadIntervalTimeout = 100;
\r
10183 ct.ReadTotalTimeoutMultiplier = 0;
\r
10184 ct.ReadTotalTimeoutConstant = 0;
\r
10185 ct.WriteTotalTimeoutMultiplier = 0;
\r
10186 ct.WriteTotalTimeoutConstant = 0;
\r
10187 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10189 /* Prepare return value */
\r
10190 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10191 cp->kind = CPComm;
\r
10194 *pr = (ProcRef *) cp;
\r
10200 OpenLoopback(ProcRef *pr)
\r
10202 DisplayFatalError("Not implemented", 0, 1);
\r
10208 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10212 SOCKET s, s2, s3;
\r
10213 struct sockaddr_in sa, mysa;
\r
10214 struct hostent FAR *hp;
\r
10215 unsigned short uport;
\r
10216 WORD wVersionRequested;
\r
10219 char stderrPortStr[MSG_SIZ];
\r
10221 /* Initialize socket DLL */
\r
10222 wVersionRequested = MAKEWORD(1, 1);
\r
10223 err = WSAStartup(wVersionRequested, &wsaData);
\r
10224 if (err != 0) return err;
\r
10226 /* Resolve remote host name */
\r
10227 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10228 if (!(hp = gethostbyname(host))) {
\r
10229 unsigned int b0, b1, b2, b3;
\r
10231 err = WSAGetLastError();
\r
10233 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10234 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10235 hp->h_addrtype = AF_INET;
\r
10236 hp->h_length = 4;
\r
10237 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10238 hp->h_addr_list[0] = (char *) malloc(4);
\r
10239 hp->h_addr_list[0][0] = (char) b0;
\r
10240 hp->h_addr_list[0][1] = (char) b1;
\r
10241 hp->h_addr_list[0][2] = (char) b2;
\r
10242 hp->h_addr_list[0][3] = (char) b3;
\r
10248 sa.sin_family = hp->h_addrtype;
\r
10249 uport = (unsigned short) 514;
\r
10250 sa.sin_port = htons(uport);
\r
10251 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10253 /* Bind local socket to unused "privileged" port address
\r
10255 s = INVALID_SOCKET;
\r
10256 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10257 mysa.sin_family = AF_INET;
\r
10258 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10259 for (fromPort = 1023;; fromPort--) {
\r
10260 if (fromPort < 0) {
\r
10262 return WSAEADDRINUSE;
\r
10264 if (s == INVALID_SOCKET) {
\r
10265 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10266 err = WSAGetLastError();
\r
10271 uport = (unsigned short) fromPort;
\r
10272 mysa.sin_port = htons(uport);
\r
10273 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10274 == SOCKET_ERROR) {
\r
10275 err = WSAGetLastError();
\r
10276 if (err == WSAEADDRINUSE) continue;
\r
10280 if (connect(s, (struct sockaddr *) &sa,
\r
10281 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10282 err = WSAGetLastError();
\r
10283 if (err == WSAEADDRINUSE) {
\r
10294 /* Bind stderr local socket to unused "privileged" port address
\r
10296 s2 = INVALID_SOCKET;
\r
10297 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10298 mysa.sin_family = AF_INET;
\r
10299 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10300 for (fromPort = 1023;; fromPort--) {
\r
10301 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10302 if (fromPort < 0) {
\r
10303 (void) closesocket(s);
\r
10305 return WSAEADDRINUSE;
\r
10307 if (s2 == INVALID_SOCKET) {
\r
10308 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10309 err = WSAGetLastError();
\r
10315 uport = (unsigned short) fromPort;
\r
10316 mysa.sin_port = htons(uport);
\r
10317 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10318 == SOCKET_ERROR) {
\r
10319 err = WSAGetLastError();
\r
10320 if (err == WSAEADDRINUSE) continue;
\r
10321 (void) closesocket(s);
\r
10325 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10326 err = WSAGetLastError();
\r
10327 if (err == WSAEADDRINUSE) {
\r
10329 s2 = INVALID_SOCKET;
\r
10332 (void) closesocket(s);
\r
10333 (void) closesocket(s2);
\r
10339 prevStderrPort = fromPort; // remember port used
\r
10340 sprintf(stderrPortStr, "%d", fromPort);
\r
10342 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10343 err = WSAGetLastError();
\r
10344 (void) closesocket(s);
\r
10345 (void) closesocket(s2);
\r
10350 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10351 err = WSAGetLastError();
\r
10352 (void) closesocket(s);
\r
10353 (void) closesocket(s2);
\r
10357 if (*user == NULLCHAR) user = UserName();
\r
10358 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10359 err = WSAGetLastError();
\r
10360 (void) closesocket(s);
\r
10361 (void) closesocket(s2);
\r
10365 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10366 err = WSAGetLastError();
\r
10367 (void) closesocket(s);
\r
10368 (void) closesocket(s2);
\r
10373 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10374 err = WSAGetLastError();
\r
10375 (void) closesocket(s);
\r
10376 (void) closesocket(s2);
\r
10380 (void) closesocket(s2); /* Stop listening */
\r
10382 /* Prepare return value */
\r
10383 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10384 cp->kind = CPRcmd;
\r
10387 *pr = (ProcRef *) cp;
\r
10394 AddInputSource(ProcRef pr, int lineByLine,
\r
10395 InputCallback func, VOIDSTAR closure)
\r
10397 InputSource *is, *is2 = NULL;
\r
10398 ChildProc *cp = (ChildProc *) pr;
\r
10400 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10401 is->lineByLine = lineByLine;
\r
10403 is->closure = closure;
\r
10404 is->second = NULL;
\r
10405 is->next = is->buf;
\r
10406 if (pr == NoProc) {
\r
10407 is->kind = CPReal;
\r
10408 consoleInputSource = is;
\r
10410 is->kind = cp->kind;
\r
10412 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10413 we create all threads suspended so that the is->hThread variable can be
\r
10414 safely assigned, then let the threads start with ResumeThread.
\r
10416 switch (cp->kind) {
\r
10418 is->hFile = cp->hFrom;
\r
10419 cp->hFrom = NULL; /* now owned by InputThread */
\r
10421 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10422 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10426 is->hFile = cp->hFrom;
\r
10427 cp->hFrom = NULL; /* now owned by InputThread */
\r
10429 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10430 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10434 is->sock = cp->sock;
\r
10436 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10437 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10441 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10443 is->sock = cp->sock;
\r
10444 is->second = is2;
\r
10445 is2->sock = cp->sock2;
\r
10446 is2->second = is2;
\r
10448 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10449 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10451 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10452 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10456 if( is->hThread != NULL ) {
\r
10457 ResumeThread( is->hThread );
\r
10460 if( is2 != NULL && is2->hThread != NULL ) {
\r
10461 ResumeThread( is2->hThread );
\r
10465 return (InputSourceRef) is;
\r
10469 RemoveInputSource(InputSourceRef isr)
\r
10473 is = (InputSource *) isr;
\r
10474 is->hThread = NULL; /* tell thread to stop */
\r
10475 CloseHandle(is->hThread);
\r
10476 if (is->second != NULL) {
\r
10477 is->second->hThread = NULL;
\r
10478 CloseHandle(is->second->hThread);
\r
10484 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10487 int outCount = SOCKET_ERROR;
\r
10488 ChildProc *cp = (ChildProc *) pr;
\r
10489 static OVERLAPPED ovl;
\r
10491 if (pr == NoProc) {
\r
10492 ConsoleOutput(message, count, FALSE);
\r
10496 if (ovl.hEvent == NULL) {
\r
10497 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10499 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10501 switch (cp->kind) {
\r
10504 outCount = send(cp->sock, message, count, 0);
\r
10505 if (outCount == SOCKET_ERROR) {
\r
10506 *outError = WSAGetLastError();
\r
10508 *outError = NO_ERROR;
\r
10513 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10514 &dOutCount, NULL)) {
\r
10515 *outError = NO_ERROR;
\r
10516 outCount = (int) dOutCount;
\r
10518 *outError = GetLastError();
\r
10523 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10524 &dOutCount, &ovl);
\r
10525 if (*outError == NO_ERROR) {
\r
10526 outCount = (int) dOutCount;
\r
10534 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10537 /* Ignore delay, not implemented for WinBoard */
\r
10538 return OutputToProcess(pr, message, count, outError);
\r
10543 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10544 char *buf, int count, int error)
\r
10546 DisplayFatalError("Not implemented", 0, 1);
\r
10549 /* see wgamelist.c for Game List functions */
\r
10550 /* see wedittags.c for Edit Tags functions */
\r
10557 char buf[MSG_SIZ];
\r
10560 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10561 f = fopen(buf, "r");
\r
10563 ProcessICSInitScript(f);
\r
10571 StartAnalysisClock()
\r
10573 if (analysisTimerEvent) return;
\r
10574 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10575 (UINT) 2000, NULL);
\r
10579 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10581 static HANDLE hwndText;
\r
10583 static int sizeX, sizeY;
\r
10584 int newSizeX, newSizeY, flags;
\r
10587 switch (message) {
\r
10588 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10589 /* Initialize the dialog items */
\r
10590 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10591 SetWindowText(hDlg, analysisTitle);
\r
10592 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10593 /* Size and position the dialog */
\r
10594 if (!analysisDialog) {
\r
10595 analysisDialog = hDlg;
\r
10596 flags = SWP_NOZORDER;
\r
10597 GetClientRect(hDlg, &rect);
\r
10598 sizeX = rect.right;
\r
10599 sizeY = rect.bottom;
\r
10600 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10601 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10602 WINDOWPLACEMENT wp;
\r
10603 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10604 wp.length = sizeof(WINDOWPLACEMENT);
\r
10606 wp.showCmd = SW_SHOW;
\r
10607 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10608 wp.rcNormalPosition.left = analysisX;
\r
10609 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10610 wp.rcNormalPosition.top = analysisY;
\r
10611 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10612 SetWindowPlacement(hDlg, &wp);
\r
10614 GetClientRect(hDlg, &rect);
\r
10615 newSizeX = rect.right;
\r
10616 newSizeY = rect.bottom;
\r
10617 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10618 newSizeX, newSizeY);
\r
10619 sizeX = newSizeX;
\r
10620 sizeY = newSizeY;
\r
10625 case WM_COMMAND: /* message: received a command */
\r
10626 switch (LOWORD(wParam)) {
\r
10628 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10629 ExitAnalyzeMode();
\r
10641 newSizeX = LOWORD(lParam);
\r
10642 newSizeY = HIWORD(lParam);
\r
10643 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10644 sizeX = newSizeX;
\r
10645 sizeY = newSizeY;
\r
10648 case WM_GETMINMAXINFO:
\r
10649 /* Prevent resizing window too small */
\r
10650 mmi = (MINMAXINFO *) lParam;
\r
10651 mmi->ptMinTrackSize.x = 100;
\r
10652 mmi->ptMinTrackSize.y = 100;
\r
10659 AnalysisPopUp(char* title, char* str)
\r
10665 EngineOutputPopUp();
\r
10668 if (str == NULL) str = "";
\r
10669 p = (char *) malloc(2 * strlen(str) + 2);
\r
10672 if (*str == '\n') *q++ = '\r';
\r
10676 if (analysisText != NULL) free(analysisText);
\r
10677 analysisText = p;
\r
10679 if (analysisDialog) {
\r
10680 SetWindowText(analysisDialog, title);
\r
10681 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10682 ShowWindow(analysisDialog, SW_SHOW);
\r
10684 analysisTitle = title;
\r
10685 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10686 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10687 hwndMain, (DLGPROC)lpProc);
\r
10688 FreeProcInstance(lpProc);
\r
10690 analysisDialogUp = TRUE;
\r
10694 AnalysisPopDown()
\r
10696 if (analysisDialog) {
\r
10697 ShowWindow(analysisDialog, SW_HIDE);
\r
10699 analysisDialogUp = FALSE;
\r
10704 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10706 highlightInfo.sq[0].x = fromX;
\r
10707 highlightInfo.sq[0].y = fromY;
\r
10708 highlightInfo.sq[1].x = toX;
\r
10709 highlightInfo.sq[1].y = toY;
\r
10713 ClearHighlights()
\r
10715 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10716 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10720 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10722 premoveHighlightInfo.sq[0].x = fromX;
\r
10723 premoveHighlightInfo.sq[0].y = fromY;
\r
10724 premoveHighlightInfo.sq[1].x = toX;
\r
10725 premoveHighlightInfo.sq[1].y = toY;
\r
10729 ClearPremoveHighlights()
\r
10731 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10732 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10736 ShutDownFrontEnd()
\r
10738 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10739 DeleteClipboardTempFiles();
\r
10745 if (IsIconic(hwndMain))
\r
10746 ShowWindow(hwndMain, SW_RESTORE);
\r
10748 SetActiveWindow(hwndMain);
\r
10752 * Prototypes for animation support routines
\r
10754 static void ScreenSquare(int column, int row, POINT * pt);
\r
10755 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10756 POINT frames[], int * nFrames);
\r
10760 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10761 { // [HGM] atomic: animate blast wave
\r
10763 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10764 explodeInfo.fromX = fromX;
\r
10765 explodeInfo.fromY = fromY;
\r
10766 explodeInfo.toX = toX;
\r
10767 explodeInfo.toY = toY;
\r
10768 for(i=1; i<nFrames; i++) {
\r
10769 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10770 DrawPosition(FALSE, NULL);
\r
10771 Sleep(appData.animSpeed);
\r
10773 explodeInfo.radius = 0;
\r
10774 DrawPosition(TRUE, NULL);
\r
10777 #define kFactor 4
\r
10780 AnimateMove(board, fromX, fromY, toX, toY)
\r
10787 ChessSquare piece;
\r
10788 POINT start, finish, mid;
\r
10789 POINT frames[kFactor * 2 + 1];
\r
10792 if (!appData.animate) return;
\r
10793 if (doingSizing) return;
\r
10794 if (fromY < 0 || fromX < 0) return;
\r
10795 piece = board[fromY][fromX];
\r
10796 if (piece >= EmptySquare) return;
\r
10798 ScreenSquare(fromX, fromY, &start);
\r
10799 ScreenSquare(toX, toY, &finish);
\r
10801 /* All pieces except knights move in straight line */
\r
10802 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10803 mid.x = start.x + (finish.x - start.x) / 2;
\r
10804 mid.y = start.y + (finish.y - start.y) / 2;
\r
10806 /* Knight: make diagonal movement then straight */
\r
10807 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10808 mid.x = start.x + (finish.x - start.x) / 2;
\r
10809 mid.y = finish.y;
\r
10811 mid.x = finish.x;
\r
10812 mid.y = start.y + (finish.y - start.y) / 2;
\r
10816 /* Don't use as many frames for very short moves */
\r
10817 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10818 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10820 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10822 animInfo.from.x = fromX;
\r
10823 animInfo.from.y = fromY;
\r
10824 animInfo.to.x = toX;
\r
10825 animInfo.to.y = toY;
\r
10826 animInfo.lastpos = start;
\r
10827 animInfo.piece = piece;
\r
10828 for (n = 0; n < nFrames; n++) {
\r
10829 animInfo.pos = frames[n];
\r
10830 DrawPosition(FALSE, NULL);
\r
10831 animInfo.lastpos = animInfo.pos;
\r
10832 Sleep(appData.animSpeed);
\r
10834 animInfo.pos = finish;
\r
10835 DrawPosition(FALSE, NULL);
\r
10836 animInfo.piece = EmptySquare;
\r
10837 if(gameInfo.variant == VariantAtomic &&
\r
10838 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10839 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10842 /* Convert board position to corner of screen rect and color */
\r
10845 ScreenSquare(column, row, pt)
\r
10846 int column; int row; POINT * pt;
\r
10849 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10850 pt->y = lineGap + row * (squareSize + lineGap);
\r
10852 pt->x = lineGap + column * (squareSize + lineGap);
\r
10853 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10857 /* Generate a series of frame coords from start->mid->finish.
\r
10858 The movement rate doubles until the half way point is
\r
10859 reached, then halves back down to the final destination,
\r
10860 which gives a nice slow in/out effect. The algorithmn
\r
10861 may seem to generate too many intermediates for short
\r
10862 moves, but remember that the purpose is to attract the
\r
10863 viewers attention to the piece about to be moved and
\r
10864 then to where it ends up. Too few frames would be less
\r
10868 Tween(start, mid, finish, factor, frames, nFrames)
\r
10869 POINT * start; POINT * mid;
\r
10870 POINT * finish; int factor;
\r
10871 POINT frames[]; int * nFrames;
\r
10873 int n, fraction = 1, count = 0;
\r
10875 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10876 for (n = 0; n < factor; n++)
\r
10878 for (n = 0; n < factor; n++) {
\r
10879 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10880 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10882 fraction = fraction / 2;
\r
10886 frames[count] = *mid;
\r
10889 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10891 for (n = 0; n < factor; n++) {
\r
10892 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10893 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10895 fraction = fraction * 2;
\r
10897 *nFrames = count;
\r
10901 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10903 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10905 EvalGraphSet( first, last, current, pvInfoList );
\r
10908 void SetProgramStats( FrontEndProgramStats * stats )
\r
10910 EngineOutputUpdate( stats );
\r