2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
291 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
292 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
293 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
294 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 BOOLEAN commentDialogUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 BOOLEAN engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1396 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1397 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1398 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1399 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1400 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1401 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1402 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1403 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1404 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1405 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1406 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1407 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1408 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1409 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1410 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1411 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1412 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1413 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1414 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1415 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1416 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1417 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1418 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1419 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1420 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1421 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1422 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1423 /* [AS] Layout stuff */
\r
1424 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1425 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1426 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1427 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1428 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1430 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1431 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1432 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1433 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1434 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1436 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1437 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1438 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1439 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1440 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1442 { NULL, ArgNone, NULL, FALSE }
\r
1446 /* Kludge for indirection files on command line */
\r
1447 char* lastIndirectionFilename;
\r
1448 ArgDescriptor argDescriptorIndirection =
\r
1449 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1453 ExitArgError(char *msg, char *badArg)
\r
1455 char buf[MSG_SIZ];
\r
1457 sprintf(buf, "%s %s", msg, badArg);
\r
1458 DisplayFatalError(buf, 0, 2);
\r
1462 /* Command line font name parser. NULL name means do nothing.
\r
1463 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1464 For backward compatibility, syntax without the colon is also
\r
1465 accepted, but font names with digits in them won't work in that case.
\r
1468 ParseFontName(char *name, MyFontParams *mfp)
\r
1471 if (name == NULL) return;
\r
1473 q = strchr(p, ':');
\r
1475 if (q - p >= sizeof(mfp->faceName))
\r
1476 ExitArgError("Font name too long:", name);
\r
1477 memcpy(mfp->faceName, p, q - p);
\r
1478 mfp->faceName[q - p] = NULLCHAR;
\r
1481 q = mfp->faceName;
\r
1482 while (*p && !isdigit(*p)) {
\r
1484 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1485 ExitArgError("Font name too long:", name);
\r
1487 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1490 if (!*p) ExitArgError("Font point size missing:", name);
\r
1491 mfp->pointSize = (float) atof(p);
\r
1492 mfp->bold = (strchr(p, 'b') != NULL);
\r
1493 mfp->italic = (strchr(p, 'i') != NULL);
\r
1494 mfp->underline = (strchr(p, 'u') != NULL);
\r
1495 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1498 /* Color name parser.
\r
1499 X version accepts X color names, but this one
\r
1500 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1502 ParseColorName(char *name)
\r
1504 int red, green, blue, count;
\r
1505 char buf[MSG_SIZ];
\r
1507 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1509 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1510 &red, &green, &blue);
\r
1513 sprintf(buf, "Can't parse color name %s", name);
\r
1514 DisplayError(buf, 0);
\r
1515 return RGB(0, 0, 0);
\r
1517 return PALETTERGB(red, green, blue);
\r
1521 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1523 char *e = argValue;
\r
1527 if (*e == 'b') eff |= CFE_BOLD;
\r
1528 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1529 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1530 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1531 else if (*e == '#' || isdigit(*e)) break;
\r
1535 *color = ParseColorName(e);
\r
1540 ParseBoardSize(char *name)
\r
1542 BoardSize bs = SizeTiny;
\r
1543 while (sizeInfo[bs].name != NULL) {
\r
1544 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1547 ExitArgError("Unrecognized board size value", name);
\r
1548 return bs; /* not reached */
\r
1553 StringGet(void *getClosure)
\r
1555 char **p = (char **) getClosure;
\r
1560 FileGet(void *getClosure)
\r
1563 FILE* f = (FILE*) getClosure;
\r
1566 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1573 /* Parse settings file named "name". If file found, return the
\r
1574 full name in fullname and return TRUE; else return FALSE */
\r
1576 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1580 int ok; char buf[MSG_SIZ];
\r
1582 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1583 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1584 sprintf(buf, "%s.ini", name);
\r
1585 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1588 f = fopen(fullname, "r");
\r
1590 ParseArgs(FileGet, f);
\r
1599 ParseArgs(GetFunc get, void *cl)
\r
1601 char argName[ARG_MAX];
\r
1602 char argValue[ARG_MAX];
\r
1603 ArgDescriptor *ad;
\r
1612 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1613 if (ch == NULLCHAR) break;
\r
1615 /* Comment to end of line */
\r
1617 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1619 } else if (ch == '/' || ch == '-') {
\r
1622 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1623 ch != '\n' && ch != '\t') {
\r
1629 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1630 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1632 if (ad->argName == NULL)
\r
1633 ExitArgError("Unrecognized argument", argName);
\r
1635 } else if (ch == '@') {
\r
1636 /* Indirection file */
\r
1637 ad = &argDescriptorIndirection;
\r
1640 /* Positional argument */
\r
1641 ad = &argDescriptors[posarg++];
\r
1642 strcpy(argName, ad->argName);
\r
1645 if (ad->argType == ArgTrue) {
\r
1646 *(Boolean *) ad->argLoc = TRUE;
\r
1649 if (ad->argType == ArgFalse) {
\r
1650 *(Boolean *) ad->argLoc = FALSE;
\r
1654 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1655 if (ch == NULLCHAR || ch == '\n') {
\r
1656 ExitArgError("No value provided for argument", argName);
\r
1660 // Quoting with { }. No characters have to (or can) be escaped.
\r
1661 // Thus the string cannot contain a '}' character.
\r
1681 } else if (ch == '\'' || ch == '"') {
\r
1682 // Quoting with ' ' or " ", with \ as escape character.
\r
1683 // Inconvenient for long strings that may contain Windows filenames.
\r
1700 if (ch == start) {
\r
1709 if (ad->argType == ArgFilename
\r
1710 || ad->argType == ArgSettingsFilename) {
\r
1716 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1740 for (i = 0; i < 3; i++) {
\r
1741 if (ch >= '0' && ch <= '7') {
\r
1742 octval = octval*8 + (ch - '0');
\r
1749 *q++ = (char) octval;
\r
1760 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1767 switch (ad->argType) {
\r
1769 *(int *) ad->argLoc = atoi(argValue);
\r
1773 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1781 *(int *) ad->argLoc = atoi(argValue);
\r
1782 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1786 *(float *) ad->argLoc = (float) atof(argValue);
\r
1791 *(char **) ad->argLoc = strdup(argValue);
\r
1794 case ArgSettingsFilename:
\r
1796 char fullname[MSG_SIZ];
\r
1797 if (ParseSettingsFile(argValue, fullname)) {
\r
1798 if (ad->argLoc != NULL) {
\r
1799 *(char **) ad->argLoc = strdup(fullname);
\r
1802 if (ad->argLoc != NULL) {
\r
1804 ExitArgError("Failed to open indirection file", argValue);
\r
1811 switch (argValue[0]) {
\r
1814 *(Boolean *) ad->argLoc = TRUE;
\r
1818 *(Boolean *) ad->argLoc = FALSE;
\r
1821 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1827 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1830 case ArgAttribs: {
\r
1831 ColorClass cc = (ColorClass)ad->argLoc;
\r
1832 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1836 case ArgBoardSize:
\r
1837 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1841 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1844 case ArgCommSettings:
\r
1845 ParseCommSettings(argValue, &dcb);
\r
1849 ExitArgError("Unrecognized argument", argValue);
\r
1858 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1860 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1861 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1864 lf->lfEscapement = 0;
\r
1865 lf->lfOrientation = 0;
\r
1866 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1867 lf->lfItalic = mfp->italic;
\r
1868 lf->lfUnderline = mfp->underline;
\r
1869 lf->lfStrikeOut = mfp->strikeout;
\r
1870 lf->lfCharSet = DEFAULT_CHARSET;
\r
1871 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1872 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1873 lf->lfQuality = DEFAULT_QUALITY;
\r
1874 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1875 strcpy(lf->lfFaceName, mfp->faceName);
\r
1879 CreateFontInMF(MyFont *mf)
\r
1881 LFfromMFP(&mf->lf, &mf->mfp);
\r
1882 if (mf->hf) DeleteObject(mf->hf);
\r
1883 mf->hf = CreateFontIndirect(&mf->lf);
\r
1887 SetDefaultTextAttribs()
\r
1890 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1891 ParseAttribs(&textAttribs[cc].color,
\r
1892 &textAttribs[cc].effects,
\r
1893 defaultTextAttribs[cc]);
\r
1898 SetDefaultSounds()
\r
1902 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1903 textAttribs[cc].sound.name = strdup("");
\r
1904 textAttribs[cc].sound.data = NULL;
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 sounds[sc].name = strdup("");
\r
1908 sounds[sc].data = NULL;
\r
1910 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 MyLoadSound(&textAttribs[cc].sound);
\r
1921 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1922 MyLoadSound(&sounds[sc]);
\r
1927 InitAppData(LPSTR lpCmdLine)
\r
1930 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1933 programName = szAppName;
\r
1935 /* Initialize to defaults */
\r
1936 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1937 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1938 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1939 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1940 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1941 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1942 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1943 SetDefaultTextAttribs();
\r
1944 SetDefaultSounds();
\r
1945 appData.movesPerSession = MOVES_PER_SESSION;
\r
1946 appData.initString = INIT_STRING;
\r
1947 appData.secondInitString = INIT_STRING;
\r
1948 appData.firstComputerString = COMPUTER_STRING;
\r
1949 appData.secondComputerString = COMPUTER_STRING;
\r
1950 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1951 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1952 appData.firstPlaysBlack = FALSE;
\r
1953 appData.noChessProgram = FALSE;
\r
1954 chessProgram = FALSE;
\r
1955 appData.firstHost = FIRST_HOST;
\r
1956 appData.secondHost = SECOND_HOST;
\r
1957 appData.firstDirectory = FIRST_DIRECTORY;
\r
1958 appData.secondDirectory = SECOND_DIRECTORY;
\r
1959 appData.bitmapDirectory = "";
\r
1960 appData.remoteShell = REMOTE_SHELL;
\r
1961 appData.remoteUser = "";
\r
1962 appData.timeDelay = TIME_DELAY;
\r
1963 appData.timeControl = TIME_CONTROL;
\r
1964 appData.timeIncrement = TIME_INCREMENT;
\r
1965 appData.icsActive = FALSE;
\r
1966 appData.icsHost = "";
\r
1967 appData.icsPort = ICS_PORT;
\r
1968 appData.icsCommPort = ICS_COMM_PORT;
\r
1969 appData.icsLogon = ICS_LOGON;
\r
1970 appData.icsHelper = "";
\r
1971 appData.useTelnet = FALSE;
\r
1972 appData.telnetProgram = TELNET_PROGRAM;
\r
1973 appData.gateway = "";
\r
1974 appData.loadGameFile = "";
\r
1975 appData.loadGameIndex = 0;
\r
1976 appData.saveGameFile = "";
\r
1977 appData.autoSaveGames = FALSE;
\r
1978 appData.loadPositionFile = "";
\r
1979 appData.loadPositionIndex = 1;
\r
1980 appData.savePositionFile = "";
\r
1981 appData.matchMode = FALSE;
\r
1982 appData.matchGames = 0;
\r
1983 appData.monoMode = FALSE;
\r
1984 appData.debugMode = FALSE;
\r
1985 appData.clockMode = TRUE;
\r
1986 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1987 appData.Iconic = FALSE; /*unused*/
\r
1988 appData.searchTime = "";
\r
1989 appData.searchDepth = 0;
\r
1990 appData.showCoords = FALSE;
\r
1991 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1992 appData.autoCallFlag = FALSE;
\r
1993 appData.flipView = FALSE;
\r
1994 appData.autoFlipView = TRUE;
\r
1995 appData.cmailGameName = "";
\r
1996 appData.alwaysPromoteToQueen = FALSE;
\r
1997 appData.oldSaveStyle = FALSE;
\r
1998 appData.quietPlay = FALSE;
\r
1999 appData.showThinking = FALSE;
\r
2000 appData.ponderNextMove = TRUE;
\r
2001 appData.periodicUpdates = TRUE;
\r
2002 appData.popupExitMessage = TRUE;
\r
2003 appData.popupMoveErrors = FALSE;
\r
2004 appData.autoObserve = FALSE;
\r
2005 appData.autoComment = FALSE;
\r
2006 appData.animate = TRUE;
\r
2007 appData.animSpeed = 10;
\r
2008 appData.animateDragging = TRUE;
\r
2009 appData.highlightLastMove = TRUE;
\r
2010 appData.getMoveList = TRUE;
\r
2011 appData.testLegality = TRUE;
\r
2012 appData.premove = TRUE;
\r
2013 appData.premoveWhite = FALSE;
\r
2014 appData.premoveWhiteText = "";
\r
2015 appData.premoveBlack = FALSE;
\r
2016 appData.premoveBlackText = "";
\r
2017 appData.icsAlarm = TRUE;
\r
2018 appData.icsAlarmTime = 5000;
\r
2019 appData.autoRaiseBoard = TRUE;
\r
2020 appData.localLineEditing = TRUE;
\r
2021 appData.colorize = TRUE;
\r
2022 appData.reuseFirst = TRUE;
\r
2023 appData.reuseSecond = TRUE;
\r
2024 appData.blindfold = FALSE;
\r
2025 appData.icsEngineAnalyze = FALSE;
\r
2026 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2027 dcb.DCBlength = sizeof(DCB);
\r
2028 dcb.BaudRate = 9600;
\r
2029 dcb.fBinary = TRUE;
\r
2030 dcb.fParity = FALSE;
\r
2031 dcb.fOutxCtsFlow = FALSE;
\r
2032 dcb.fOutxDsrFlow = FALSE;
\r
2033 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2034 dcb.fDsrSensitivity = FALSE;
\r
2035 dcb.fTXContinueOnXoff = TRUE;
\r
2036 dcb.fOutX = FALSE;
\r
2038 dcb.fNull = FALSE;
\r
2039 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2040 dcb.fAbortOnError = FALSE;
\r
2042 dcb.Parity = SPACEPARITY;
\r
2043 dcb.StopBits = ONESTOPBIT;
\r
2044 settingsFileName = SETTINGS_FILE;
\r
2045 saveSettingsOnExit = TRUE;
\r
2046 boardX = CW_USEDEFAULT;
\r
2047 boardY = CW_USEDEFAULT;
\r
2048 analysisX = CW_USEDEFAULT;
\r
2049 analysisY = CW_USEDEFAULT;
\r
2050 analysisW = CW_USEDEFAULT;
\r
2051 analysisH = CW_USEDEFAULT;
\r
2052 commentX = CW_USEDEFAULT;
\r
2053 commentY = CW_USEDEFAULT;
\r
2054 commentW = CW_USEDEFAULT;
\r
2055 commentH = CW_USEDEFAULT;
\r
2056 editTagsX = CW_USEDEFAULT;
\r
2057 editTagsY = CW_USEDEFAULT;
\r
2058 editTagsW = CW_USEDEFAULT;
\r
2059 editTagsH = CW_USEDEFAULT;
\r
2060 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2061 icsNames = ICS_NAMES;
\r
2062 firstChessProgramNames = FCP_NAMES;
\r
2063 secondChessProgramNames = SCP_NAMES;
\r
2064 appData.initialMode = "";
\r
2065 appData.variant = "normal";
\r
2066 appData.firstProtocolVersion = PROTOVER;
\r
2067 appData.secondProtocolVersion = PROTOVER;
\r
2068 appData.showButtonBar = TRUE;
\r
2070 /* [AS] New properties (see comments in header file) */
\r
2071 appData.firstScoreIsAbsolute = FALSE;
\r
2072 appData.secondScoreIsAbsolute = FALSE;
\r
2073 appData.saveExtendedInfoInPGN = FALSE;
\r
2074 appData.hideThinkingFromHuman = FALSE;
\r
2075 appData.liteBackTextureFile = "";
\r
2076 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2077 appData.darkBackTextureFile = "";
\r
2078 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2079 appData.renderPiecesWithFont = "";
\r
2080 appData.fontToPieceTable = "";
\r
2081 appData.fontBackColorWhite = 0;
\r
2082 appData.fontForeColorWhite = 0;
\r
2083 appData.fontBackColorBlack = 0;
\r
2084 appData.fontForeColorBlack = 0;
\r
2085 appData.fontPieceSize = 80;
\r
2086 appData.overrideLineGap = 1;
\r
2087 appData.adjudicateLossThreshold = 0;
\r
2088 appData.delayBeforeQuit = 0;
\r
2089 appData.delayAfterQuit = 0;
\r
2090 appData.nameOfDebugFile = "winboard.debug";
\r
2091 appData.pgnEventHeader = "Computer Chess Game";
\r
2092 appData.defaultFrcPosition = -1;
\r
2093 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2094 appData.saveOutOfBookInfo = TRUE;
\r
2095 appData.showEvalInMoveHistory = TRUE;
\r
2096 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2097 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2098 appData.highlightMoveWithArrow = FALSE;
\r
2099 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2100 appData.useStickyWindows = TRUE;
\r
2101 appData.adjudicateDrawMoves = 0;
\r
2102 appData.autoDisplayComment = TRUE;
\r
2103 appData.autoDisplayTags = TRUE;
\r
2104 appData.firstIsUCI = FALSE;
\r
2105 appData.secondIsUCI = FALSE;
\r
2106 appData.firstHasOwnBookUCI = TRUE;
\r
2107 appData.secondHasOwnBookUCI = TRUE;
\r
2108 appData.polyglotDir = "";
\r
2109 appData.usePolyglotBook = FALSE;
\r
2110 appData.polyglotBook = "";
\r
2111 appData.defaultHashSize = 64;
\r
2112 appData.defaultCacheSizeEGTB = 4;
\r
2113 appData.defaultPathEGTB = "c:\\egtb";
\r
2114 appData.firstOptions = "";
\r
2115 appData.secondOptions = "";
\r
2117 InitWindowPlacement( &wpGameList );
\r
2118 InitWindowPlacement( &wpMoveHistory );
\r
2119 InitWindowPlacement( &wpEvalGraph );
\r
2120 InitWindowPlacement( &wpEngineOutput );
\r
2121 InitWindowPlacement( &wpConsole );
\r
2123 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2124 appData.NrFiles = -1;
\r
2125 appData.NrRanks = -1;
\r
2126 appData.holdingsSize = -1;
\r
2127 appData.testClaims = FALSE;
\r
2128 appData.checkMates = FALSE;
\r
2129 appData.materialDraws= FALSE;
\r
2130 appData.trivialDraws = FALSE;
\r
2131 appData.ruleMoves = 51;
\r
2132 appData.drawRepeats = 6;
\r
2133 appData.matchPause = 10000;
\r
2134 appData.alphaRank = FALSE;
\r
2135 appData.allWhite = FALSE;
\r
2136 appData.upsideDown = FALSE;
\r
2137 appData.serverPause = 15;
\r
2138 appData.serverMovesName = NULL;
\r
2139 appData.suppressLoadMoves = FALSE;
\r
2140 appData.firstTimeOdds = 1;
\r
2141 appData.secondTimeOdds = 1;
\r
2142 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2143 appData.secondAccumulateTC = 1;
\r
2144 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2145 appData.secondNPS = -1;
\r
2146 appData.engineComments = 1;
\r
2147 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2148 appData.egtFormats = "";
\r
2151 appData.zippyTalk = ZIPPY_TALK;
\r
2152 appData.zippyPlay = ZIPPY_PLAY;
\r
2153 appData.zippyLines = ZIPPY_LINES;
\r
2154 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2155 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2156 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2157 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2158 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2159 appData.zippyUseI = ZIPPY_USE_I;
\r
2160 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2161 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2162 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2163 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2164 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2165 appData.zippyAbort = ZIPPY_ABORT;
\r
2166 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2167 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2168 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2171 /* Point font array elements to structures and
\r
2172 parse default font names */
\r
2173 for (i=0; i<NUM_FONTS; i++) {
\r
2174 for (j=0; j<NUM_SIZES; j++) {
\r
2175 font[j][i] = &fontRec[j][i];
\r
2176 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2180 /* Parse default settings file if any */
\r
2181 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2182 settingsFileName = strdup(buf);
\r
2185 /* Parse command line */
\r
2186 ParseArgs(StringGet, &lpCmdLine);
\r
2188 /* [HGM] make sure board size is acceptable */
\r
2189 if(appData.NrFiles > BOARD_SIZE ||
\r
2190 appData.NrRanks > BOARD_SIZE )
\r
2191 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2193 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2194 * with options from the command line, we now make an even higher priority
\r
2195 * overrule by WB options attached to the engine command line. This so that
\r
2196 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2199 if(appData.firstChessProgram != NULL) {
\r
2200 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2201 static char *f = "first";
\r
2202 char buf[MSG_SIZ], *q = buf;
\r
2203 if(p != NULL) { // engine command line contains WinBoard options
\r
2204 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2205 ParseArgs(StringGet, &q);
\r
2206 p[-1] = 0; // cut them offengine command line
\r
2209 // now do same for second chess program
\r
2210 if(appData.secondChessProgram != NULL) {
\r
2211 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2212 static char *s = "second";
\r
2213 char buf[MSG_SIZ], *q = buf;
\r
2214 if(p != NULL) { // engine command line contains WinBoard options
\r
2215 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2216 ParseArgs(StringGet, &q);
\r
2217 p[-1] = 0; // cut them offengine command line
\r
2222 /* Propagate options that affect others */
\r
2223 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2224 if (appData.icsActive || appData.noChessProgram) {
\r
2225 chessProgram = FALSE; /* not local chess program mode */
\r
2228 /* Open startup dialog if needed */
\r
2229 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2230 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2231 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2232 *appData.secondChessProgram == NULLCHAR))) {
\r
2235 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2236 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2237 FreeProcInstance(lpProc);
\r
2240 /* Make sure save files land in the right (?) directory */
\r
2241 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2242 appData.saveGameFile = strdup(buf);
\r
2244 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.savePositionFile = strdup(buf);
\r
2248 /* Finish initialization for fonts and sounds */
\r
2249 for (i=0; i<NUM_FONTS; i++) {
\r
2250 for (j=0; j<NUM_SIZES; j++) {
\r
2251 CreateFontInMF(font[j][i]);
\r
2254 /* xboard, and older WinBoards, controlled the move sound with the
\r
2255 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2256 always turn the option on (so that the backend will call us),
\r
2257 then let the user turn the sound off by setting it to silence if
\r
2258 desired. To accommodate old winboard.ini files saved by old
\r
2259 versions of WinBoard, we also turn off the sound if the option
\r
2260 was initially set to false. */
\r
2261 if (!appData.ringBellAfterMoves) {
\r
2262 sounds[(int)SoundMove].name = strdup("");
\r
2263 appData.ringBellAfterMoves = TRUE;
\r
2265 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2266 SetCurrentDirectory(installDir);
\r
2268 SetCurrentDirectory(currDir);
\r
2270 p = icsTextMenuString;
\r
2271 if (p[0] == '@') {
\r
2272 FILE* f = fopen(p + 1, "r");
\r
2274 DisplayFatalError(p + 1, errno, 2);
\r
2277 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2279 buf[i] = NULLCHAR;
\r
2282 ParseIcsTextMenu(strdup(p));
\r
2289 HMENU hmenu = GetMenu(hwndMain);
\r
2291 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2292 MF_BYCOMMAND|((appData.icsActive &&
\r
2293 *appData.icsCommPort != NULLCHAR) ?
\r
2294 MF_ENABLED : MF_GRAYED));
\r
2295 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2296 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2297 MF_CHECKED : MF_UNCHECKED));
\r
2302 SaveSettings(char* name)
\r
2305 ArgDescriptor *ad;
\r
2306 WINDOWPLACEMENT wp;
\r
2307 char dir[MSG_SIZ];
\r
2309 if (!hwndMain) return;
\r
2311 GetCurrentDirectory(MSG_SIZ, dir);
\r
2312 SetCurrentDirectory(installDir);
\r
2313 f = fopen(name, "w");
\r
2314 SetCurrentDirectory(dir);
\r
2316 DisplayError(name, errno);
\r
2319 fprintf(f, ";\n");
\r
2320 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2321 fprintf(f, ";\n");
\r
2322 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2323 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2324 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2325 fprintf(f, ";\n");
\r
2327 wp.length = sizeof(WINDOWPLACEMENT);
\r
2328 GetWindowPlacement(hwndMain, &wp);
\r
2329 boardX = wp.rcNormalPosition.left;
\r
2330 boardY = wp.rcNormalPosition.top;
\r
2332 if (hwndConsole) {
\r
2333 GetWindowPlacement(hwndConsole, &wp);
\r
2334 wpConsole.x = wp.rcNormalPosition.left;
\r
2335 wpConsole.y = wp.rcNormalPosition.top;
\r
2336 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2337 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2340 if (analysisDialog) {
\r
2341 GetWindowPlacement(analysisDialog, &wp);
\r
2342 analysisX = wp.rcNormalPosition.left;
\r
2343 analysisY = wp.rcNormalPosition.top;
\r
2344 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2345 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2348 if (commentDialog) {
\r
2349 GetWindowPlacement(commentDialog, &wp);
\r
2350 commentX = wp.rcNormalPosition.left;
\r
2351 commentY = wp.rcNormalPosition.top;
\r
2352 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (editTagsDialog) {
\r
2357 GetWindowPlacement(editTagsDialog, &wp);
\r
2358 editTagsX = wp.rcNormalPosition.left;
\r
2359 editTagsY = wp.rcNormalPosition.top;
\r
2360 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (gameListDialog) {
\r
2365 GetWindowPlacement(gameListDialog, &wp);
\r
2366 wpGameList.x = wp.rcNormalPosition.left;
\r
2367 wpGameList.y = wp.rcNormalPosition.top;
\r
2368 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 /* [AS] Move history */
\r
2373 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2375 if( moveHistoryDialog ) {
\r
2376 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2377 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2378 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2379 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2380 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2383 /* [AS] Eval graph */
\r
2384 wpEvalGraph.visible = EvalGraphIsUp();
\r
2386 if( evalGraphDialog ) {
\r
2387 GetWindowPlacement(evalGraphDialog, &wp);
\r
2388 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2389 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2390 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2391 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2394 /* [AS] Engine output */
\r
2395 wpEngineOutput.visible = EngineOutputIsUp();
\r
2397 if( engineOutputDialog ) {
\r
2398 GetWindowPlacement(engineOutputDialog, &wp);
\r
2399 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2400 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2401 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2402 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2405 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2406 if (!ad->save) continue;
\r
2407 switch (ad->argType) {
\r
2410 char *p = *(char **)ad->argLoc;
\r
2411 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2412 /* Quote multiline values or \-containing values
\r
2413 with { } if possible */
\r
2414 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2416 /* Else quote with " " */
\r
2417 fprintf(f, "/%s=\"", ad->argName);
\r
2419 if (*p == '\n') fprintf(f, "\n");
\r
2420 else if (*p == '\r') fprintf(f, "\\r");
\r
2421 else if (*p == '\t') fprintf(f, "\\t");
\r
2422 else if (*p == '\b') fprintf(f, "\\b");
\r
2423 else if (*p == '\f') fprintf(f, "\\f");
\r
2424 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2425 else if (*p == '\"') fprintf(f, "\\\"");
\r
2426 else if (*p == '\\') fprintf(f, "\\\\");
\r
2430 fprintf(f, "\"\n");
\r
2436 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2445 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2448 fprintf(f, "/%s=%s\n", ad->argName,
\r
2449 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2452 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2455 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2460 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2461 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2466 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2467 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2468 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2469 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2470 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2471 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2472 (ta->effects) ? " " : "",
\r
2473 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2477 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2478 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2480 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2483 case ArgBoardSize:
\r
2484 fprintf(f, "/%s=%s\n", ad->argName,
\r
2485 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2490 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2491 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2492 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2493 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2494 ad->argName, mfp->faceName, mfp->pointSize,
\r
2495 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2496 mfp->bold ? "b" : "",
\r
2497 mfp->italic ? "i" : "",
\r
2498 mfp->underline ? "u" : "",
\r
2499 mfp->strikeout ? "s" : "");
\r
2503 case ArgCommSettings:
\r
2504 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2506 case ArgSettingsFilename: ;
\r
2514 /*---------------------------------------------------------------------------*\
\r
2516 * GDI board drawing routines
\r
2518 \*---------------------------------------------------------------------------*/
\r
2520 /* [AS] Draw square using background texture */
\r
2521 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2526 return; /* Should never happen! */
\r
2529 SetGraphicsMode( dst, GM_ADVANCED );
\r
2536 /* X reflection */
\r
2541 x.eDx = (FLOAT) dw + dx - 1;
\r
2544 SetWorldTransform( dst, &x );
\r
2547 /* Y reflection */
\r
2553 x.eDy = (FLOAT) dh + dy - 1;
\r
2555 SetWorldTransform( dst, &x );
\r
2563 x.eDx = (FLOAT) dx;
\r
2564 x.eDy = (FLOAT) dy;
\r
2567 SetWorldTransform( dst, &x );
\r
2571 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2579 SetWorldTransform( dst, &x );
\r
2581 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2584 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2586 PM_WP = (int) WhitePawn,
\r
2587 PM_WN = (int) WhiteKnight,
\r
2588 PM_WB = (int) WhiteBishop,
\r
2589 PM_WR = (int) WhiteRook,
\r
2590 PM_WQ = (int) WhiteQueen,
\r
2591 PM_WF = (int) WhiteFerz,
\r
2592 PM_WW = (int) WhiteWazir,
\r
2593 PM_WE = (int) WhiteAlfil,
\r
2594 PM_WM = (int) WhiteMan,
\r
2595 PM_WO = (int) WhiteCannon,
\r
2596 PM_WU = (int) WhiteUnicorn,
\r
2597 PM_WH = (int) WhiteNightrider,
\r
2598 PM_WA = (int) WhiteAngel,
\r
2599 PM_WC = (int) WhiteMarshall,
\r
2600 PM_WAB = (int) WhiteCardinal,
\r
2601 PM_WD = (int) WhiteDragon,
\r
2602 PM_WL = (int) WhiteLance,
\r
2603 PM_WS = (int) WhiteCobra,
\r
2604 PM_WV = (int) WhiteFalcon,
\r
2605 PM_WSG = (int) WhiteSilver,
\r
2606 PM_WG = (int) WhiteGrasshopper,
\r
2607 PM_WK = (int) WhiteKing,
\r
2608 PM_BP = (int) BlackPawn,
\r
2609 PM_BN = (int) BlackKnight,
\r
2610 PM_BB = (int) BlackBishop,
\r
2611 PM_BR = (int) BlackRook,
\r
2612 PM_BQ = (int) BlackQueen,
\r
2613 PM_BF = (int) BlackFerz,
\r
2614 PM_BW = (int) BlackWazir,
\r
2615 PM_BE = (int) BlackAlfil,
\r
2616 PM_BM = (int) BlackMan,
\r
2617 PM_BO = (int) BlackCannon,
\r
2618 PM_BU = (int) BlackUnicorn,
\r
2619 PM_BH = (int) BlackNightrider,
\r
2620 PM_BA = (int) BlackAngel,
\r
2621 PM_BC = (int) BlackMarshall,
\r
2622 PM_BG = (int) BlackGrasshopper,
\r
2623 PM_BAB = (int) BlackCardinal,
\r
2624 PM_BD = (int) BlackDragon,
\r
2625 PM_BL = (int) BlackLance,
\r
2626 PM_BS = (int) BlackCobra,
\r
2627 PM_BV = (int) BlackFalcon,
\r
2628 PM_BSG = (int) BlackSilver,
\r
2629 PM_BK = (int) BlackKing
\r
2632 static HFONT hPieceFont = NULL;
\r
2633 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2634 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2635 static int fontBitmapSquareSize = 0;
\r
2636 static char pieceToFontChar[(int) EmptySquare] =
\r
2637 { 'p', 'n', 'b', 'r', 'q',
\r
2638 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2639 'k', 'o', 'm', 'v', 't', 'w',
\r
2640 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2643 extern BOOL SetCharTable( char *table, const char * map );
\r
2644 /* [HGM] moved to backend.c */
\r
2646 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2649 BYTE r1 = GetRValue( color );
\r
2650 BYTE g1 = GetGValue( color );
\r
2651 BYTE b1 = GetBValue( color );
\r
2657 /* Create a uniform background first */
\r
2658 hbrush = CreateSolidBrush( color );
\r
2659 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject( hbrush );
\r
2664 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2665 int steps = squareSize / 2;
\r
2668 for( i=0; i<steps; i++ ) {
\r
2669 BYTE r = r1 - (r1-r2) * i / steps;
\r
2670 BYTE g = g1 - (g1-g2) * i / steps;
\r
2671 BYTE b = b1 - (b1-b2) * i / steps;
\r
2673 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2674 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2675 FillRect( hdc, &rc, hbrush );
\r
2676 DeleteObject(hbrush);
\r
2679 else if( mode == 2 ) {
\r
2680 /* Diagonal gradient, good more or less for every piece */
\r
2681 POINT triangle[3];
\r
2682 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2683 HBRUSH hbrush_old;
\r
2684 int steps = squareSize;
\r
2687 triangle[0].x = squareSize - steps;
\r
2688 triangle[0].y = squareSize;
\r
2689 triangle[1].x = squareSize;
\r
2690 triangle[1].y = squareSize;
\r
2691 triangle[2].x = squareSize;
\r
2692 triangle[2].y = squareSize - steps;
\r
2694 for( i=0; i<steps; i++ ) {
\r
2695 BYTE r = r1 - (r1-r2) * i / steps;
\r
2696 BYTE g = g1 - (g1-g2) * i / steps;
\r
2697 BYTE b = b1 - (b1-b2) * i / steps;
\r
2699 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2700 hbrush_old = SelectObject( hdc, hbrush );
\r
2701 Polygon( hdc, triangle, 3 );
\r
2702 SelectObject( hdc, hbrush_old );
\r
2703 DeleteObject(hbrush);
\r
2708 SelectObject( hdc, hpen );
\r
2713 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2714 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2715 piece: follow the steps as explained below.
\r
2717 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2721 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2725 int backColor = whitePieceColor;
\r
2726 int foreColor = blackPieceColor;
\r
2728 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2729 backColor = appData.fontBackColorWhite;
\r
2730 foreColor = appData.fontForeColorWhite;
\r
2732 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2733 backColor = appData.fontBackColorBlack;
\r
2734 foreColor = appData.fontForeColorBlack;
\r
2738 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2740 hbm_old = SelectObject( hdc, hbm );
\r
2744 rc.right = squareSize;
\r
2745 rc.bottom = squareSize;
\r
2747 /* Step 1: background is now black */
\r
2748 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2750 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2752 pt.x = (squareSize - sz.cx) / 2;
\r
2753 pt.y = (squareSize - sz.cy) / 2;
\r
2755 SetBkMode( hdc, TRANSPARENT );
\r
2756 SetTextColor( hdc, chroma );
\r
2757 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2758 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2760 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2761 /* Step 3: the area outside the piece is filled with white */
\r
2762 // FloodFill( hdc, 0, 0, chroma );
\r
2763 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2764 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2765 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2766 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2767 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2769 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2770 but if the start point is not inside the piece we're lost!
\r
2771 There should be a better way to do this... if we could create a region or path
\r
2772 from the fill operation we would be fine for example.
\r
2774 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2775 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2777 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2778 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2779 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2781 SelectObject( dc2, bm2 );
\r
2782 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2783 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2786 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 DeleteObject( bm2 );
\r
2792 SetTextColor( hdc, 0 );
\r
2794 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2795 draw the piece again in black for safety.
\r
2797 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2799 SelectObject( hdc, hbm_old );
\r
2801 if( hPieceMask[index] != NULL ) {
\r
2802 DeleteObject( hPieceMask[index] );
\r
2805 hPieceMask[index] = hbm;
\r
2808 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2810 SelectObject( hdc, hbm );
\r
2813 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2814 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2815 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2817 SelectObject( dc1, hPieceMask[index] );
\r
2818 SelectObject( dc2, bm2 );
\r
2819 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2820 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2823 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2824 the piece background and deletes (makes transparent) the rest.
\r
2825 Thanks to that mask, we are free to paint the background with the greates
\r
2826 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2827 We use this, to make gradients and give the pieces a "roundish" look.
\r
2829 SetPieceBackground( hdc, backColor, 2 );
\r
2830 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2834 DeleteObject( bm2 );
\r
2837 SetTextColor( hdc, foreColor );
\r
2838 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2840 SelectObject( hdc, hbm_old );
\r
2842 if( hPieceFace[index] != NULL ) {
\r
2843 DeleteObject( hPieceFace[index] );
\r
2846 hPieceFace[index] = hbm;
\r
2849 static int TranslatePieceToFontPiece( int piece )
\r
2879 case BlackMarshall:
\r
2883 case BlackNightrider:
\r
2889 case BlackUnicorn:
\r
2893 case BlackGrasshopper:
\r
2905 case BlackCardinal:
\r
2912 case WhiteMarshall:
\r
2916 case WhiteNightrider:
\r
2922 case WhiteUnicorn:
\r
2926 case WhiteGrasshopper:
\r
2938 case WhiteCardinal:
\r
2947 void CreatePiecesFromFont()
\r
2950 HDC hdc_window = NULL;
\r
2956 if( fontBitmapSquareSize < 0 ) {
\r
2957 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2961 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2962 fontBitmapSquareSize = -1;
\r
2966 if( fontBitmapSquareSize != squareSize ) {
\r
2967 hdc_window = GetDC( hwndMain );
\r
2968 hdc = CreateCompatibleDC( hdc_window );
\r
2970 if( hPieceFont != NULL ) {
\r
2971 DeleteObject( hPieceFont );
\r
2974 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2975 hPieceMask[i] = NULL;
\r
2976 hPieceFace[i] = NULL;
\r
2982 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2983 fontHeight = appData.fontPieceSize;
\r
2986 fontHeight = (fontHeight * squareSize) / 100;
\r
2988 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2990 lf.lfEscapement = 0;
\r
2991 lf.lfOrientation = 0;
\r
2992 lf.lfWeight = FW_NORMAL;
\r
2994 lf.lfUnderline = 0;
\r
2995 lf.lfStrikeOut = 0;
\r
2996 lf.lfCharSet = DEFAULT_CHARSET;
\r
2997 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2998 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2999 lf.lfQuality = PROOF_QUALITY;
\r
3000 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3001 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3002 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3004 hPieceFont = CreateFontIndirect( &lf );
\r
3006 if( hPieceFont == NULL ) {
\r
3007 fontBitmapSquareSize = -2;
\r
3010 /* Setup font-to-piece character table */
\r
3011 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3012 /* No (or wrong) global settings, try to detect the font */
\r
3013 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3015 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3017 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3018 /* DiagramTT* family */
\r
3019 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3021 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3022 /* Fairy symbols */
\r
3023 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3025 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3026 /* Good Companion (Some characters get warped as literal :-( */
\r
3027 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3028 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3029 SetCharTable(pieceToFontChar, s);
\r
3032 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3033 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3037 /* Create bitmaps */
\r
3038 hfont_old = SelectObject( hdc, hPieceFont );
\r
3039 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3040 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3043 SelectObject( hdc, hfont_old );
\r
3045 fontBitmapSquareSize = squareSize;
\r
3049 if( hdc != NULL ) {
\r
3053 if( hdc_window != NULL ) {
\r
3054 ReleaseDC( hwndMain, hdc_window );
\r
3059 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3063 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3064 if (gameInfo.event &&
\r
3065 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3066 strcmp(name, "k80s") == 0) {
\r
3067 strcpy(name, "tim");
\r
3069 return LoadBitmap(hinst, name);
\r
3073 /* Insert a color into the program's logical palette
\r
3074 structure. This code assumes the given color is
\r
3075 the result of the RGB or PALETTERGB macro, and it
\r
3076 knows how those macros work (which is documented).
\r
3079 InsertInPalette(COLORREF color)
\r
3081 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3083 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3084 DisplayFatalError("Too many colors", 0, 1);
\r
3085 pLogPal->palNumEntries--;
\r
3089 pe->peFlags = (char) 0;
\r
3090 pe->peRed = (char) (0xFF & color);
\r
3091 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3092 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3098 InitDrawingColors()
\r
3100 if (pLogPal == NULL) {
\r
3101 /* Allocate enough memory for a logical palette with
\r
3102 * PALETTESIZE entries and set the size and version fields
\r
3103 * of the logical palette structure.
\r
3105 pLogPal = (NPLOGPALETTE)
\r
3106 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3107 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3108 pLogPal->palVersion = 0x300;
\r
3110 pLogPal->palNumEntries = 0;
\r
3112 InsertInPalette(lightSquareColor);
\r
3113 InsertInPalette(darkSquareColor);
\r
3114 InsertInPalette(whitePieceColor);
\r
3115 InsertInPalette(blackPieceColor);
\r
3116 InsertInPalette(highlightSquareColor);
\r
3117 InsertInPalette(premoveHighlightColor);
\r
3119 /* create a logical color palette according the information
\r
3120 * in the LOGPALETTE structure.
\r
3122 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3124 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3125 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3126 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3127 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3128 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3129 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3130 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3131 /* [AS] Force rendering of the font-based pieces */
\r
3132 if( fontBitmapSquareSize > 0 ) {
\r
3133 fontBitmapSquareSize = 0;
\r
3139 BoardWidth(int boardSize, int n)
\r
3140 { /* [HGM] argument n added to allow different width and height */
\r
3141 int lineGap = sizeInfo[boardSize].lineGap;
\r
3143 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3144 lineGap = appData.overrideLineGap;
\r
3147 return (n + 1) * lineGap +
\r
3148 n * sizeInfo[boardSize].squareSize;
\r
3151 /* Respond to board resize by dragging edge */
\r
3153 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3155 BoardSize newSize = NUM_SIZES - 1;
\r
3156 static int recurse = 0;
\r
3157 if (IsIconic(hwndMain)) return;
\r
3158 if (recurse > 0) return;
\r
3160 while (newSize > 0) {
\r
3161 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3162 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3163 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3166 boardSize = newSize;
\r
3167 InitDrawingSizes(boardSize, flags);
\r
3174 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3176 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3177 ChessSquare piece;
\r
3178 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3180 SIZE clockSize, messageSize;
\r
3182 char buf[MSG_SIZ];
\r
3184 HMENU hmenu = GetMenu(hwndMain);
\r
3185 RECT crect, wrect, oldRect;
\r
3187 LOGBRUSH logbrush;
\r
3189 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3190 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3192 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3193 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3195 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3196 oldRect.top = boardY;
\r
3197 oldRect.right = boardX + winWidth;
\r
3198 oldRect.bottom = boardY + winHeight;
\r
3200 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3201 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3202 squareSize = sizeInfo[boardSize].squareSize;
\r
3203 lineGap = sizeInfo[boardSize].lineGap;
\r
3204 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3206 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3207 lineGap = appData.overrideLineGap;
\r
3210 if (tinyLayout != oldTinyLayout) {
\r
3211 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3213 style &= ~WS_SYSMENU;
\r
3214 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3215 "&Minimize\tCtrl+F4");
\r
3217 style |= WS_SYSMENU;
\r
3218 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3220 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3222 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3223 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3224 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3226 DrawMenuBar(hwndMain);
\r
3229 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3230 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3232 /* Get text area sizes */
\r
3233 hdc = GetDC(hwndMain);
\r
3234 if (appData.clockMode) {
\r
3235 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3237 sprintf(buf, "White");
\r
3239 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3240 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3241 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3242 str = "We only care about the height here";
\r
3243 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3244 SelectObject(hdc, oldFont);
\r
3245 ReleaseDC(hwndMain, hdc);
\r
3247 /* Compute where everything goes */
\r
3248 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3249 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3250 logoHeight = 2*clockSize.cy;
\r
3251 leftLogoRect.left = OUTER_MARGIN;
\r
3252 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3253 leftLogoRect.top = OUTER_MARGIN;
\r
3254 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3256 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3257 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3258 rightLogoRect.top = OUTER_MARGIN;
\r
3259 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3262 whiteRect.left = leftLogoRect.right;
\r
3263 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3264 whiteRect.top = OUTER_MARGIN;
\r
3265 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3267 blackRect.right = rightLogoRect.left;
\r
3268 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3269 blackRect.top = whiteRect.top;
\r
3270 blackRect.bottom = whiteRect.bottom;
\r
3272 whiteRect.left = OUTER_MARGIN;
\r
3273 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3274 whiteRect.top = OUTER_MARGIN;
\r
3275 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3277 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3278 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3279 blackRect.top = whiteRect.top;
\r
3280 blackRect.bottom = whiteRect.bottom;
\r
3283 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3284 if (appData.showButtonBar) {
\r
3285 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3286 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3288 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3290 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3291 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3293 boardRect.left = OUTER_MARGIN;
\r
3294 boardRect.right = boardRect.left + boardWidth;
\r
3295 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3296 boardRect.bottom = boardRect.top + boardHeight;
\r
3298 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3299 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3300 oldBoardSize = boardSize;
\r
3301 oldTinyLayout = tinyLayout;
\r
3302 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3303 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3304 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3305 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3306 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3307 winHeight = winH; // without disturbing window attachments
\r
3308 GetWindowRect(hwndMain, &wrect);
\r
3309 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3310 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3312 // [HGM] placement: let attached windows follow size change.
\r
3313 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3314 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3315 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3319 /* compensate if menu bar wrapped */
\r
3320 GetClientRect(hwndMain, &crect);
\r
3321 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3322 winHeight += offby;
\r
3324 case WMSZ_TOPLEFT:
\r
3325 SetWindowPos(hwndMain, NULL,
\r
3326 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3327 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3330 case WMSZ_TOPRIGHT:
\r
3332 SetWindowPos(hwndMain, NULL,
\r
3333 wrect.left, wrect.bottom - winHeight,
\r
3334 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3337 case WMSZ_BOTTOMLEFT:
\r
3339 SetWindowPos(hwndMain, NULL,
\r
3340 wrect.right - winWidth, wrect.top,
\r
3341 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3344 case WMSZ_BOTTOMRIGHT:
\r
3348 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3349 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3354 for (i = 0; i < N_BUTTONS; i++) {
\r
3355 if (buttonDesc[i].hwnd != NULL) {
\r
3356 DestroyWindow(buttonDesc[i].hwnd);
\r
3357 buttonDesc[i].hwnd = NULL;
\r
3359 if (appData.showButtonBar) {
\r
3360 buttonDesc[i].hwnd =
\r
3361 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3362 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3363 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3364 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3365 (HMENU) buttonDesc[i].id,
\r
3366 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3368 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3369 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3370 MAKELPARAM(FALSE, 0));
\r
3372 if (buttonDesc[i].id == IDM_Pause)
\r
3373 hwndPause = buttonDesc[i].hwnd;
\r
3374 buttonDesc[i].wndproc = (WNDPROC)
\r
3375 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3378 if (gridPen != NULL) DeleteObject(gridPen);
\r
3379 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3380 if (premovePen != NULL) DeleteObject(premovePen);
\r
3381 if (lineGap != 0) {
\r
3382 logbrush.lbStyle = BS_SOLID;
\r
3383 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3385 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3386 lineGap, &logbrush, 0, NULL);
\r
3387 logbrush.lbColor = highlightSquareColor;
\r
3389 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3390 lineGap, &logbrush, 0, NULL);
\r
3392 logbrush.lbColor = premoveHighlightColor;
\r
3394 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3395 lineGap, &logbrush, 0, NULL);
\r
3397 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3398 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3399 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3400 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3401 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3402 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3403 BOARD_WIDTH * (squareSize + lineGap);
\r
3404 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3406 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3407 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3408 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3409 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3410 lineGap / 2 + (i * (squareSize + lineGap));
\r
3411 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3412 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3413 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3417 /* [HGM] Licensing requirement */
\r
3419 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3422 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3424 GothicPopUp( "", VariantNormal);
\r
3427 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3429 /* Load piece bitmaps for this board size */
\r
3430 for (i=0; i<=2; i++) {
\r
3431 for (piece = WhitePawn;
\r
3432 (int) piece < (int) BlackPawn;
\r
3433 piece = (ChessSquare) ((int) piece + 1)) {
\r
3434 if (pieceBitmap[i][piece] != NULL)
\r
3435 DeleteObject(pieceBitmap[i][piece]);
\r
3439 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3440 // Orthodox Chess pieces
\r
3441 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3442 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3443 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3444 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3446 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3451 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3452 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3454 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3456 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3457 // in Shogi, Hijack the unused Queen for Lance
\r
3458 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3459 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3460 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3462 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3463 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3464 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3467 if(squareSize <= 72 && squareSize >= 33) {
\r
3468 /* A & C are available in most sizes now */
\r
3469 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3470 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3482 } else { // Smirf-like
\r
3483 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3487 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3488 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3491 } else { // WinBoard standard
\r
3492 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3499 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3500 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3515 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3531 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3532 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3559 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3560 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3561 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3562 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3563 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3564 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3565 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3566 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3567 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3568 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3569 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3570 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3577 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3578 /* special Shogi support in this size */
\r
3579 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3580 for (piece = WhitePawn;
\r
3581 (int) piece < (int) BlackPawn;
\r
3582 piece = (ChessSquare) ((int) piece + 1)) {
\r
3583 if (pieceBitmap[i][piece] != NULL)
\r
3584 DeleteObject(pieceBitmap[i][piece]);
\r
3587 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3588 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3589 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3590 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3601 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3602 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3603 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3604 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3615 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3616 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3617 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3618 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3634 PieceBitmap(ChessSquare p, int kind)
\r
3636 if ((int) p >= (int) BlackPawn)
\r
3637 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3639 return pieceBitmap[kind][(int) p];
\r
3642 /***************************************************************/
\r
3644 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3645 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3647 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3648 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3652 SquareToPos(int row, int column, int * x, int * y)
\r
3655 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3656 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3658 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3659 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3664 DrawCoordsOnDC(HDC hdc)
\r
3666 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3667 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3668 char str[2] = { NULLCHAR, NULLCHAR };
\r
3669 int oldMode, oldAlign, x, y, start, i;
\r
3673 if (!appData.showCoords)
\r
3676 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3678 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3679 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3680 oldAlign = GetTextAlign(hdc);
\r
3681 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3683 y = boardRect.top + lineGap;
\r
3684 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3686 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3687 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3688 str[0] = files[start + i];
\r
3689 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3690 y += squareSize + lineGap;
\r
3693 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3695 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3696 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3697 str[0] = ranks[start + i];
\r
3698 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3699 x += squareSize + lineGap;
\r
3702 SelectObject(hdc, oldBrush);
\r
3703 SetBkMode(hdc, oldMode);
\r
3704 SetTextAlign(hdc, oldAlign);
\r
3705 SelectObject(hdc, oldFont);
\r
3709 DrawGridOnDC(HDC hdc)
\r
3713 if (lineGap != 0) {
\r
3714 oldPen = SelectObject(hdc, gridPen);
\r
3715 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3716 SelectObject(hdc, oldPen);
\r
3720 #define HIGHLIGHT_PEN 0
\r
3721 #define PREMOVE_PEN 1
\r
3724 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3727 HPEN oldPen, hPen;
\r
3728 if (lineGap == 0) return;
\r
3730 x1 = boardRect.left +
\r
3731 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3732 y1 = boardRect.top +
\r
3733 lineGap/2 + y * (squareSize + lineGap);
\r
3735 x1 = boardRect.left +
\r
3736 lineGap/2 + x * (squareSize + lineGap);
\r
3737 y1 = boardRect.top +
\r
3738 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3740 hPen = pen ? premovePen : highlightPen;
\r
3741 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3742 MoveToEx(hdc, x1, y1, NULL);
\r
3743 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3744 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3745 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3746 LineTo(hdc, x1, y1);
\r
3747 SelectObject(hdc, oldPen);
\r
3751 DrawHighlightsOnDC(HDC hdc)
\r
3754 for (i=0; i<2; i++) {
\r
3755 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3756 DrawHighlightOnDC(hdc, TRUE,
\r
3757 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3760 for (i=0; i<2; i++) {
\r
3761 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3762 premoveHighlightInfo.sq[i].y >= 0) {
\r
3763 DrawHighlightOnDC(hdc, TRUE,
\r
3764 premoveHighlightInfo.sq[i].x,
\r
3765 premoveHighlightInfo.sq[i].y,
\r
3771 /* Note: sqcolor is used only in monoMode */
\r
3772 /* Note that this code is largely duplicated in woptions.c,
\r
3773 function DrawSampleSquare, so that needs to be updated too */
\r
3775 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3777 HBITMAP oldBitmap;
\r
3781 if (appData.blindfold) return;
\r
3783 /* [AS] Use font-based pieces if needed */
\r
3784 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3785 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3786 CreatePiecesFromFont();
\r
3788 if( fontBitmapSquareSize == squareSize ) {
\r
3789 int index = TranslatePieceToFontPiece(piece);
\r
3791 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3795 squareSize, squareSize,
\r
3800 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3804 squareSize, squareSize,
\r
3813 if (appData.monoMode) {
\r
3814 SelectObject(tmphdc, PieceBitmap(piece,
\r
3815 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3816 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3817 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3819 tmpSize = squareSize;
\r
3821 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3822 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3823 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3824 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3825 x += (squareSize - minorSize)>>1;
\r
3826 y += squareSize - minorSize - 2;
\r
3827 tmpSize = minorSize;
\r
3829 if (color || appData.allWhite ) {
\r
3830 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3832 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3833 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3834 if(appData.upsideDown && color==flipView)
\r
3835 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3837 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3838 /* Use black for outline of white pieces */
\r
3839 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3840 if(appData.upsideDown && color==flipView)
\r
3841 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3843 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3845 /* Use square color for details of black pieces */
\r
3846 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3847 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3848 if(appData.upsideDown && !flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3853 SelectObject(hdc, oldBrush);
\r
3854 SelectObject(tmphdc, oldBitmap);
\r
3858 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3859 int GetBackTextureMode( int algo )
\r
3861 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3865 case BACK_TEXTURE_MODE_PLAIN:
\r
3866 result = 1; /* Always use identity map */
\r
3868 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3869 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3877 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3878 to handle redraws cleanly (as random numbers would always be different).
\r
3880 VOID RebuildTextureSquareInfo()
\r
3890 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3892 if( liteBackTexture != NULL ) {
\r
3893 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3894 lite_w = bi.bmWidth;
\r
3895 lite_h = bi.bmHeight;
\r
3899 if( darkBackTexture != NULL ) {
\r
3900 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3901 dark_w = bi.bmWidth;
\r
3902 dark_h = bi.bmHeight;
\r
3906 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3907 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3908 if( (col + row) & 1 ) {
\r
3910 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3911 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3912 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3913 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3918 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3928 /* [AS] Arrow highlighting support */
\r
3930 static int A_WIDTH = 5; /* Width of arrow body */
\r
3932 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3933 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3935 static double Sqr( double x )
\r
3940 static int Round( double x )
\r
3942 return (int) (x + 0.5);
\r
3945 /* Draw an arrow between two points using current settings */
\r
3946 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3949 double dx, dy, j, k, x, y;
\r
3951 if( d_x == s_x ) {
\r
3952 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3954 arrow[0].x = s_x + A_WIDTH;
\r
3957 arrow[1].x = s_x + A_WIDTH;
\r
3958 arrow[1].y = d_y - h;
\r
3960 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3961 arrow[2].y = d_y - h;
\r
3966 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3967 arrow[4].y = d_y - h;
\r
3969 arrow[5].x = s_x - A_WIDTH;
\r
3970 arrow[5].y = d_y - h;
\r
3972 arrow[6].x = s_x - A_WIDTH;
\r
3975 else if( d_y == s_y ) {
\r
3976 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3979 arrow[0].y = s_y + A_WIDTH;
\r
3981 arrow[1].x = d_x - w;
\r
3982 arrow[1].y = s_y + A_WIDTH;
\r
3984 arrow[2].x = d_x - w;
\r
3985 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3990 arrow[4].x = d_x - w;
\r
3991 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3993 arrow[5].x = d_x - w;
\r
3994 arrow[5].y = s_y - A_WIDTH;
\r
3997 arrow[6].y = s_y - A_WIDTH;
\r
4000 /* [AS] Needed a lot of paper for this! :-) */
\r
4001 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4002 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4004 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4006 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4011 arrow[0].x = Round(x - j);
\r
4012 arrow[0].y = Round(y + j*dx);
\r
4014 arrow[1].x = Round(x + j);
\r
4015 arrow[1].y = Round(y - j*dx);
\r
4018 x = (double) d_x - k;
\r
4019 y = (double) d_y - k*dy;
\r
4022 x = (double) d_x + k;
\r
4023 y = (double) d_y + k*dy;
\r
4026 arrow[2].x = Round(x + j);
\r
4027 arrow[2].y = Round(y - j*dx);
\r
4029 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4030 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4035 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4036 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4038 arrow[6].x = Round(x - j);
\r
4039 arrow[6].y = Round(y + j*dx);
\r
4042 Polygon( hdc, arrow, 7 );
\r
4045 /* [AS] Draw an arrow between two squares */
\r
4046 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4048 int s_x, s_y, d_x, d_y;
\r
4055 if( s_col == d_col && s_row == d_row ) {
\r
4059 /* Get source and destination points */
\r
4060 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4061 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4064 d_y += squareSize / 4;
\r
4066 else if( d_y < s_y ) {
\r
4067 d_y += 3 * squareSize / 4;
\r
4070 d_y += squareSize / 2;
\r
4074 d_x += squareSize / 4;
\r
4076 else if( d_x < s_x ) {
\r
4077 d_x += 3 * squareSize / 4;
\r
4080 d_x += squareSize / 2;
\r
4083 s_x += squareSize / 2;
\r
4084 s_y += squareSize / 2;
\r
4086 /* Adjust width */
\r
4087 A_WIDTH = squareSize / 14;
\r
4090 stLB.lbStyle = BS_SOLID;
\r
4091 stLB.lbColor = appData.highlightArrowColor;
\r
4094 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4095 holdpen = SelectObject( hdc, hpen );
\r
4096 hbrush = CreateBrushIndirect( &stLB );
\r
4097 holdbrush = SelectObject( hdc, hbrush );
\r
4099 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4101 SelectObject( hdc, holdpen );
\r
4102 SelectObject( hdc, holdbrush );
\r
4103 DeleteObject( hpen );
\r
4104 DeleteObject( hbrush );
\r
4107 BOOL HasHighlightInfo()
\r
4109 BOOL result = FALSE;
\r
4111 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4112 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4120 BOOL IsDrawArrowEnabled()
\r
4122 BOOL result = FALSE;
\r
4124 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4131 VOID DrawArrowHighlight( HDC hdc )
\r
4133 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4134 DrawArrowBetweenSquares( hdc,
\r
4135 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4136 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4140 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4142 HRGN result = NULL;
\r
4144 if( HasHighlightInfo() ) {
\r
4145 int x1, y1, x2, y2;
\r
4146 int sx, sy, dx, dy;
\r
4148 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4149 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4151 sx = MIN( x1, x2 );
\r
4152 sy = MIN( y1, y2 );
\r
4153 dx = MAX( x1, x2 ) + squareSize;
\r
4154 dy = MAX( y1, y2 ) + squareSize;
\r
4156 result = CreateRectRgn( sx, sy, dx, dy );
\r
4163 Warning: this function modifies the behavior of several other functions.
\r
4165 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4166 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4167 repaint is scattered all over the place, which is not good for features such as
\r
4168 "arrow highlighting" that require a full repaint of the board.
\r
4170 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4171 user interaction, when speed is not so important) but especially to avoid errors
\r
4172 in the displayed graphics.
\r
4174 In such patched places, I always try refer to this function so there is a single
\r
4175 place to maintain knowledge.
\r
4177 To restore the original behavior, just return FALSE unconditionally.
\r
4179 BOOL IsFullRepaintPreferrable()
\r
4181 BOOL result = FALSE;
\r
4183 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4184 /* Arrow may appear on the board */
\r
4192 This function is called by DrawPosition to know whether a full repaint must
\r
4195 Only DrawPosition may directly call this function, which makes use of
\r
4196 some state information. Other function should call DrawPosition specifying
\r
4197 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4199 BOOL DrawPositionNeedsFullRepaint()
\r
4201 BOOL result = FALSE;
\r
4204 Probably a slightly better policy would be to trigger a full repaint
\r
4205 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4206 but animation is fast enough that it's difficult to notice.
\r
4208 if( animInfo.piece == EmptySquare ) {
\r
4209 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4218 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4220 int row, column, x, y, square_color, piece_color;
\r
4221 ChessSquare piece;
\r
4223 HDC texture_hdc = NULL;
\r
4225 /* [AS] Initialize background textures if needed */
\r
4226 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4227 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4228 if( backTextureSquareSize != squareSize
\r
4229 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4230 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4231 backTextureSquareSize = squareSize;
\r
4232 RebuildTextureSquareInfo();
\r
4235 texture_hdc = CreateCompatibleDC( hdc );
\r
4238 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4239 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4241 SquareToPos(row, column, &x, &y);
\r
4243 piece = board[row][column];
\r
4245 square_color = ((column + row) % 2) == 1;
\r
4246 if( gameInfo.variant == VariantXiangqi ) {
\r
4247 square_color = !InPalace(row, column);
\r
4248 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4249 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4251 piece_color = (int) piece < (int) BlackPawn;
\r
4254 /* [HGM] holdings file: light square or black */
\r
4255 if(column == BOARD_LEFT-2) {
\r
4256 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4259 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4263 if(column == BOARD_RGHT + 1 ) {
\r
4264 if( row < gameInfo.holdingsSize )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4271 if(column == BOARD_LEFT-1 ) /* left align */
\r
4272 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4273 else if( column == BOARD_RGHT) /* right align */
\r
4274 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4276 if (appData.monoMode) {
\r
4277 if (piece == EmptySquare) {
\r
4278 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4279 square_color ? WHITENESS : BLACKNESS);
\r
4281 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4284 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4285 /* [AS] Draw the square using a texture bitmap */
\r
4286 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4287 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4288 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4291 squareSize, squareSize,
\r
4294 backTextureSquareInfo[r][c].mode,
\r
4295 backTextureSquareInfo[r][c].x,
\r
4296 backTextureSquareInfo[r][c].y );
\r
4298 SelectObject( texture_hdc, hbm );
\r
4300 if (piece != EmptySquare) {
\r
4301 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4305 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4307 oldBrush = SelectObject(hdc, brush );
\r
4308 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4309 SelectObject(hdc, oldBrush);
\r
4310 if (piece != EmptySquare)
\r
4311 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4316 if( texture_hdc != NULL ) {
\r
4317 DeleteDC( texture_hdc );
\r
4321 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4322 void fputDW(FILE *f, int x)
\r
4324 fputc(x & 255, f);
\r
4325 fputc(x>>8 & 255, f);
\r
4326 fputc(x>>16 & 255, f);
\r
4327 fputc(x>>24 & 255, f);
\r
4330 #define MAX_CLIPS 200 /* more than enough */
\r
4333 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4335 // HBITMAP bufferBitmap;
\r
4340 int w = 100, h = 50;
\r
4342 if(logo == NULL) return;
\r
4343 // GetClientRect(hwndMain, &Rect);
\r
4344 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4345 // Rect.bottom-Rect.top+1);
\r
4346 tmphdc = CreateCompatibleDC(hdc);
\r
4347 hbm = SelectObject(tmphdc, logo);
\r
4348 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4352 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4353 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4354 SelectObject(tmphdc, hbm);
\r
4359 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4361 static Board lastReq, lastDrawn;
\r
4362 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4363 static int lastDrawnFlipView = 0;
\r
4364 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4365 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4368 HBITMAP bufferBitmap;
\r
4369 HBITMAP oldBitmap;
\r
4371 HRGN clips[MAX_CLIPS];
\r
4372 ChessSquare dragged_piece = EmptySquare;
\r
4374 /* I'm undecided on this - this function figures out whether a full
\r
4375 * repaint is necessary on its own, so there's no real reason to have the
\r
4376 * caller tell it that. I think this can safely be set to FALSE - but
\r
4377 * if we trust the callers not to request full repaints unnessesarily, then
\r
4378 * we could skip some clipping work. In other words, only request a full
\r
4379 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4380 * gamestart and similar) --Hawk
\r
4382 Boolean fullrepaint = repaint;
\r
4384 if( DrawPositionNeedsFullRepaint() ) {
\r
4385 fullrepaint = TRUE;
\r
4388 if (board == NULL) {
\r
4389 if (!lastReqValid) {
\r
4394 CopyBoard(lastReq, board);
\r
4398 if (doingSizing) {
\r
4402 if (IsIconic(hwndMain)) {
\r
4406 if (hdc == NULL) {
\r
4407 hdc = GetDC(hwndMain);
\r
4408 if (!appData.monoMode) {
\r
4409 SelectPalette(hdc, hPal, FALSE);
\r
4410 RealizePalette(hdc);
\r
4414 releaseDC = FALSE;
\r
4417 /* Create some work-DCs */
\r
4418 hdcmem = CreateCompatibleDC(hdc);
\r
4419 tmphdc = CreateCompatibleDC(hdc);
\r
4421 /* If dragging is in progress, we temporarely remove the piece */
\r
4422 /* [HGM] or temporarily decrease count if stacked */
\r
4423 /* !! Moved to before board compare !! */
\r
4424 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4425 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4426 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4427 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4428 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4430 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4431 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4432 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4434 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4437 /* Figure out which squares need updating by comparing the
\r
4438 * newest board with the last drawn board and checking if
\r
4439 * flipping has changed.
\r
4441 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4442 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4443 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4444 if (lastDrawn[row][column] != board[row][column]) {
\r
4445 SquareToPos(row, column, &x, &y);
\r
4446 clips[num_clips++] =
\r
4447 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4451 for (i=0; i<2; i++) {
\r
4452 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4453 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4454 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4455 lastDrawnHighlight.sq[i].y >= 0) {
\r
4456 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4457 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4458 clips[num_clips++] =
\r
4459 CreateRectRgn(x - lineGap, y - lineGap,
\r
4460 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4462 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4463 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4464 clips[num_clips++] =
\r
4465 CreateRectRgn(x - lineGap, y - lineGap,
\r
4466 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 for (i=0; i<2; i++) {
\r
4471 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4472 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4473 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4474 lastDrawnPremove.sq[i].y >= 0) {
\r
4475 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4476 lastDrawnPremove.sq[i].x, &x, &y);
\r
4477 clips[num_clips++] =
\r
4478 CreateRectRgn(x - lineGap, y - lineGap,
\r
4479 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4481 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4482 premoveHighlightInfo.sq[i].y >= 0) {
\r
4483 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4484 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4492 fullrepaint = TRUE;
\r
4495 /* Create a buffer bitmap - this is the actual bitmap
\r
4496 * being written to. When all the work is done, we can
\r
4497 * copy it to the real DC (the screen). This avoids
\r
4498 * the problems with flickering.
\r
4500 GetClientRect(hwndMain, &Rect);
\r
4501 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4502 Rect.bottom-Rect.top+1);
\r
4503 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4504 if (!appData.monoMode) {
\r
4505 SelectPalette(hdcmem, hPal, FALSE);
\r
4508 /* Create clips for dragging */
\r
4509 if (!fullrepaint) {
\r
4510 if (dragInfo.from.x >= 0) {
\r
4511 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4512 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4514 if (dragInfo.start.x >= 0) {
\r
4515 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4516 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4518 if (dragInfo.pos.x >= 0) {
\r
4519 x = dragInfo.pos.x - squareSize / 2;
\r
4520 y = dragInfo.pos.y - squareSize / 2;
\r
4521 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4523 if (dragInfo.lastpos.x >= 0) {
\r
4524 x = dragInfo.lastpos.x - squareSize / 2;
\r
4525 y = dragInfo.lastpos.y - squareSize / 2;
\r
4526 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4530 /* Are we animating a move?
\r
4532 * - remove the piece from the board (temporarely)
\r
4533 * - calculate the clipping region
\r
4535 if (!fullrepaint) {
\r
4536 if (animInfo.piece != EmptySquare) {
\r
4537 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4538 x = boardRect.left + animInfo.lastpos.x;
\r
4539 y = boardRect.top + animInfo.lastpos.y;
\r
4540 x2 = boardRect.left + animInfo.pos.x;
\r
4541 y2 = boardRect.top + animInfo.pos.y;
\r
4542 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4543 /* Slight kludge. The real problem is that after AnimateMove is
\r
4544 done, the position on the screen does not match lastDrawn.
\r
4545 This currently causes trouble only on e.p. captures in
\r
4546 atomic, where the piece moves to an empty square and then
\r
4547 explodes. The old and new positions both had an empty square
\r
4548 at the destination, but animation has drawn a piece there and
\r
4549 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4550 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4554 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4555 if (num_clips == 0)
\r
4556 fullrepaint = TRUE;
\r
4558 /* Set clipping on the memory DC */
\r
4559 if (!fullrepaint) {
\r
4560 SelectClipRgn(hdcmem, clips[0]);
\r
4561 for (x = 1; x < num_clips; x++) {
\r
4562 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4563 abort(); // this should never ever happen!
\r
4567 /* Do all the drawing to the memory DC */
\r
4568 if(explodeInfo.radius) { // [HGM] atomic
\r
4570 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4571 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4572 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4573 x += squareSize/2;
\r
4574 y += squareSize/2;
\r
4575 if(!fullrepaint) {
\r
4576 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4577 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4579 DrawGridOnDC(hdcmem);
\r
4580 DrawHighlightsOnDC(hdcmem);
\r
4581 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4582 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4583 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4584 SelectObject(hdcmem, oldBrush);
\r
4586 DrawGridOnDC(hdcmem);
\r
4587 DrawHighlightsOnDC(hdcmem);
\r
4588 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4591 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4592 if(appData.autoLogo) {
\r
4594 switch(gameMode) { // pick logos based on game mode
\r
4595 case IcsObserving:
\r
4596 whiteLogo = second.programLogo; // ICS logo
\r
4597 blackLogo = second.programLogo;
\r
4600 case IcsPlayingWhite:
\r
4601 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4602 blackLogo = second.programLogo; // ICS logo
\r
4604 case IcsPlayingBlack:
\r
4605 whiteLogo = second.programLogo; // ICS logo
\r
4606 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4608 case TwoMachinesPlay:
\r
4609 if(first.twoMachinesColor[0] == 'b') {
\r
4610 whiteLogo = second.programLogo;
\r
4611 blackLogo = first.programLogo;
\r
4614 case MachinePlaysWhite:
\r
4615 blackLogo = userLogo;
\r
4617 case MachinePlaysBlack:
\r
4618 whiteLogo = userLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4623 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4626 if( appData.highlightMoveWithArrow ) {
\r
4627 DrawArrowHighlight(hdcmem);
\r
4630 DrawCoordsOnDC(hdcmem);
\r
4632 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4633 /* to make sure lastDrawn contains what is actually drawn */
\r
4635 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4636 if (dragged_piece != EmptySquare) {
\r
4637 /* [HGM] or restack */
\r
4638 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4639 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4641 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4642 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4643 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4644 x = dragInfo.pos.x - squareSize / 2;
\r
4645 y = dragInfo.pos.y - squareSize / 2;
\r
4646 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4647 ((int) dragged_piece < (int) BlackPawn),
\r
4648 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4651 /* Put the animated piece back into place and draw it */
\r
4652 if (animInfo.piece != EmptySquare) {
\r
4653 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4654 x = boardRect.left + animInfo.pos.x;
\r
4655 y = boardRect.top + animInfo.pos.y;
\r
4656 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4657 ((int) animInfo.piece < (int) BlackPawn),
\r
4658 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4661 /* Release the bufferBitmap by selecting in the old bitmap
\r
4662 * and delete the memory DC
\r
4664 SelectObject(hdcmem, oldBitmap);
\r
4667 /* Set clipping on the target DC */
\r
4668 if (!fullrepaint) {
\r
4669 SelectClipRgn(hdc, clips[0]);
\r
4670 for (x = 1; x < num_clips; x++) {
\r
4671 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4672 abort(); // this should never ever happen!
\r
4676 /* Copy the new bitmap onto the screen in one go.
\r
4677 * This way we avoid any flickering
\r
4679 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4680 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4681 boardRect.right - boardRect.left,
\r
4682 boardRect.bottom - boardRect.top,
\r
4683 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4684 if(saveDiagFlag) {
\r
4685 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4686 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4688 GetObject(bufferBitmap, sizeof(b), &b);
\r
4689 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4690 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4691 bih.biWidth = b.bmWidth;
\r
4692 bih.biHeight = b.bmHeight;
\r
4694 bih.biBitCount = b.bmBitsPixel;
\r
4695 bih.biCompression = 0;
\r
4696 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4697 bih.biXPelsPerMeter = 0;
\r
4698 bih.biYPelsPerMeter = 0;
\r
4699 bih.biClrUsed = 0;
\r
4700 bih.biClrImportant = 0;
\r
4701 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4702 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4703 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4704 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4706 wb = b.bmWidthBytes;
\r
4708 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4709 int k = ((int*) pData)[i];
\r
4710 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4711 if(j >= 16) break;
\r
4713 if(j >= nrColors) nrColors = j+1;
\r
4715 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4717 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4718 for(w=0; w<(wb>>2); w+=2) {
\r
4719 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4720 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4721 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4722 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4723 pData[p++] = m | j<<4;
\r
4725 while(p&3) pData[p++] = 0;
\r
4728 wb = ((wb+31)>>5)<<2;
\r
4730 // write BITMAPFILEHEADER
\r
4731 fprintf(diagFile, "BM");
\r
4732 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4733 fputDW(diagFile, 0);
\r
4734 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4735 // write BITMAPINFOHEADER
\r
4736 fputDW(diagFile, 40);
\r
4737 fputDW(diagFile, b.bmWidth);
\r
4738 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4739 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4740 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 // write color table
\r
4749 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4750 // write bitmap data
\r
4751 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4752 fputc(pData[i], diagFile);
\r
4756 SelectObject(tmphdc, oldBitmap);
\r
4758 /* Massive cleanup */
\r
4759 for (x = 0; x < num_clips; x++)
\r
4760 DeleteObject(clips[x]);
\r
4763 DeleteObject(bufferBitmap);
\r
4766 ReleaseDC(hwndMain, hdc);
\r
4768 if (lastDrawnFlipView != flipView) {
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4775 /* CopyBoard(lastDrawn, board);*/
\r
4776 lastDrawnHighlight = highlightInfo;
\r
4777 lastDrawnPremove = premoveHighlightInfo;
\r
4778 lastDrawnFlipView = flipView;
\r
4779 lastDrawnValid = 1;
\r
4782 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4787 saveDiagFlag = 1; diagFile = f;
\r
4788 HDCDrawPosition(NULL, TRUE, NULL);
\r
4792 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4799 /*---------------------------------------------------------------------------*\
\r
4800 | CLIENT PAINT PROCEDURE
\r
4801 | This is the main event-handler for the WM_PAINT message.
\r
4803 \*---------------------------------------------------------------------------*/
\r
4805 PaintProc(HWND hwnd)
\r
4811 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4812 if (IsIconic(hwnd)) {
\r
4813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4815 if (!appData.monoMode) {
\r
4816 SelectPalette(hdc, hPal, FALSE);
\r
4817 RealizePalette(hdc);
\r
4819 HDCDrawPosition(hdc, 1, NULL);
\r
4821 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4822 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4823 ETO_CLIPPED|ETO_OPAQUE,
\r
4824 &messageRect, messageText, strlen(messageText), NULL);
\r
4825 SelectObject(hdc, oldFont);
\r
4826 DisplayBothClocks();
\r
4828 EndPaint(hwnd,&ps);
\r
4836 * If the user selects on a border boundary, return -1; if off the board,
\r
4837 * return -2. Otherwise map the event coordinate to the square.
\r
4838 * The offset boardRect.left or boardRect.top must already have been
\r
4839 * subtracted from x.
\r
4842 EventToSquare(int x)
\r
4849 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4851 x /= (squareSize + lineGap);
\r
4852 if (x >= BOARD_SIZE)
\r
4863 DropEnable dropEnables[] = {
\r
4864 { 'P', DP_Pawn, "Pawn" },
\r
4865 { 'N', DP_Knight, "Knight" },
\r
4866 { 'B', DP_Bishop, "Bishop" },
\r
4867 { 'R', DP_Rook, "Rook" },
\r
4868 { 'Q', DP_Queen, "Queen" },
\r
4872 SetupDropMenu(HMENU hmenu)
\r
4874 int i, count, enable;
\r
4876 extern char white_holding[], black_holding[];
\r
4877 char item[MSG_SIZ];
\r
4879 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4880 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4881 dropEnables[i].piece);
\r
4883 while (p && *p++ == dropEnables[i].piece) count++;
\r
4884 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4885 enable = count > 0 || !appData.testLegality
\r
4886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4887 && !appData.icsActive);
\r
4888 ModifyMenu(hmenu, dropEnables[i].command,
\r
4889 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4890 dropEnables[i].command, item);
\r
4894 /* Event handler for mouse messages */
\r
4896 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4900 static int recursive = 0;
\r
4902 // BOOLEAN needsRedraw = FALSE;
\r
4903 BOOLEAN saveAnimate;
\r
4904 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4905 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4906 ChessMove moveType;
\r
4909 if (message == WM_MBUTTONUP) {
\r
4910 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4911 to the middle button: we simulate pressing the left button too!
\r
4913 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4914 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4920 pt.x = LOWORD(lParam);
\r
4921 pt.y = HIWORD(lParam);
\r
4922 x = EventToSquare(pt.x - boardRect.left);
\r
4923 y = EventToSquare(pt.y - boardRect.top);
\r
4924 if (!flipView && y >= 0) {
\r
4925 y = BOARD_HEIGHT - 1 - y;
\r
4927 if (flipView && x >= 0) {
\r
4928 x = BOARD_WIDTH - 1 - x;
\r
4931 switch (message) {
\r
4932 case WM_LBUTTONDOWN:
\r
4933 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4934 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4935 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4936 if(gameInfo.holdingsWidth &&
\r
4937 (WhiteOnMove(currentMove)
\r
4938 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4939 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4940 // click in right holdings, for determining promotion piece
\r
4941 ChessSquare p = boards[currentMove][y][x];
\r
4942 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4943 if(p != EmptySquare) {
\r
4944 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4945 fromX = fromY = -1;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4953 sameAgain = FALSE;
\r
4955 /* Downclick vertically off board; check if on clock */
\r
4956 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4957 if (gameMode == EditPosition) {
\r
4958 SetWhiteToPlayEvent();
\r
4959 } else if (gameMode == IcsPlayingBlack ||
\r
4960 gameMode == MachinePlaysWhite) {
\r
4962 } else if (gameMode == EditGame) {
\r
4963 AdjustClock(flipClock, -1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditPosition) {
\r
4967 SetBlackToPlayEvent();
\r
4968 } else if (gameMode == IcsPlayingWhite ||
\r
4969 gameMode == MachinePlaysBlack) {
\r
4971 } else if (gameMode == EditGame) {
\r
4972 AdjustClock(!flipClock, -1);
\r
4975 if (!appData.highlightLastMove) {
\r
4976 ClearHighlights();
\r
4977 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4979 fromX = fromY = -1;
\r
4980 dragInfo.start.x = dragInfo.start.y = -1;
\r
4981 dragInfo.from = dragInfo.start;
\r
4983 } else if (x < 0 || y < 0
\r
4984 /* [HGM] block clicks between board and holdings */
\r
4985 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4986 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4987 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4988 /* EditPosition, empty square, or different color piece;
\r
4989 click-click move is possible */
\r
4992 } else if (fromX == x && fromY == y) {
\r
4993 /* Downclick on same square again */
\r
4994 ClearHighlights();
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4996 sameAgain = TRUE;
\r
4997 } else if (fromX != -1 &&
\r
4998 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5000 /* Downclick on different square. */
\r
5001 /* [HGM] if on holdings file, should count as new first click ! */
\r
5002 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5005 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5006 to make sure move is legal before showing promotion popup */
\r
5007 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5008 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5009 fromX = fromY = -1;
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, boards[currentMove]);
\r
5014 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5015 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5016 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5017 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5018 appData.alwaysPromoteToQueen)) {
\r
5019 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5020 if (!appData.highlightLastMove) {
\r
5021 ClearHighlights();
\r
5022 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5025 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5026 SetHighlights(fromX, fromY, toX, toY);
\r
5027 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5028 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5029 If promotion to Q is legal, all are legal! */
\r
5030 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5031 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5032 // kludge to temporarily execute move on display, without promoting yet
\r
5033 promotionChoice = TRUE;
\r
5034 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5035 boards[currentMove][toY][toX] = p;
\r
5036 DrawPosition(FALSE, boards[currentMove]);
\r
5037 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5038 boards[currentMove][toY][toX] = q;
\r
5039 DisplayMessage("Select piece from holdings", "");
\r
5041 PromotionPopup(hwnd);
\r
5043 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5044 if (appData.animate || appData.highlightLastMove) {
\r
5045 SetHighlights(fromX, fromY, toX, toY);
\r
5047 ClearHighlights();
\r
5049 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5050 if (appData.animate && !appData.highlightLastMove) {
\r
5051 ClearHighlights();
\r
5052 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5055 fromX = fromY = -1;
\r
5059 if (gotPremove && moveType != Comment) {
\r
5060 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5062 } else ClearHighlights();
\r
5063 fromX = fromY = -1;
\r
5064 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5065 if(moveType != Comment) break;
\r
5067 /* First downclick, or restart on a square with same color piece */
\r
5068 if (!frozen && OKToStartUserMove(x, y)) {
\r
5071 dragInfo.lastpos = pt;
\r
5072 dragInfo.from.x = fromX;
\r
5073 dragInfo.from.y = fromY;
\r
5074 dragInfo.start = dragInfo.from;
\r
5075 SetCapture(hwndMain);
\r
5077 fromX = fromY = -1;
\r
5078 dragInfo.start.x = dragInfo.start.y = -1;
\r
5079 dragInfo.from = dragInfo.start;
\r
5080 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5084 case WM_LBUTTONUP:
\r
5086 if (fromX == -1) break;
\r
5087 if (x == fromX && y == fromY) {
\r
5088 dragInfo.from.x = dragInfo.from.y = -1;
\r
5089 /* Upclick on same square */
\r
5091 /* Clicked same square twice: abort click-click move */
\r
5092 fromX = fromY = -1;
\r
5094 ClearPremoveHighlights();
\r
5096 /* First square clicked: start click-click move */
\r
5097 SetHighlights(fromX, fromY, -1, -1);
\r
5099 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5100 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5101 /* Errant click; ignore */
\r
5104 /* Finish drag move. */
\r
5105 if (appData.debugMode) {
\r
5106 fprintf(debugFP, "release\n");
\r
5108 dragInfo.from.x = dragInfo.from.y = -1;
\r
5111 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5112 appData.animate = appData.animate && !appData.animateDragging;
\r
5113 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5114 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5115 fromX = fromY = -1;
\r
5116 ClearHighlights();
\r
5117 DrawPosition(FALSE, boards[currentMove]);
\r
5118 appData.animate = saveAnimate;
\r
5121 if(moveType != ImpossibleMove) {
\r
5122 /* [HGM] use move type to determine if move is promotion.
\r
5123 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5124 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5125 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5126 appData.alwaysPromoteToQueen))
\r
5127 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5129 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5130 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5132 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5133 // kludge to temporarily execute move on display, wthout promotng yet
\r
5134 promotionChoice = TRUE;
\r
5135 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5136 boards[currentMove][toY][toX] = p;
\r
5137 DrawPosition(FALSE, boards[currentMove]);
\r
5138 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5139 boards[currentMove][toY][toX] = q;
\r
5140 appData.animate = saveAnimate;
\r
5141 DisplayMessage("Select piece from holdings", "");
\r
5144 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5146 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5147 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5148 moveType == WhiteCapturesEnPassant ||
\r
5149 moveType == BlackCapturesEnPassant ) )
\r
5150 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5151 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5154 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5155 appData.animate = saveAnimate;
\r
5156 fromX = fromY = -1;
\r
5157 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5158 ClearHighlights();
\r
5160 if (appData.animate || appData.animateDragging ||
\r
5161 appData.highlightDragging || gotPremove) {
\r
5162 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5165 dragInfo.start.x = dragInfo.start.y = -1;
\r
5166 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5169 case WM_MOUSEMOVE:
\r
5170 if ((appData.animateDragging || appData.highlightDragging)
\r
5171 && (wParam & MK_LBUTTON)
\r
5172 && dragInfo.from.x >= 0)
\r
5174 BOOL full_repaint = FALSE;
\r
5176 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5177 if (appData.animateDragging) {
\r
5178 dragInfo.pos = pt;
\r
5180 if (appData.highlightDragging) {
\r
5181 SetHighlights(fromX, fromY, x, y);
\r
5182 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5183 full_repaint = TRUE;
\r
5187 DrawPosition( full_repaint, NULL);
\r
5189 dragInfo.lastpos = dragInfo.pos;
\r
5193 case WM_MOUSEWHEEL: // [DM]
\r
5194 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5195 /* Mouse Wheel is being rolled forward
\r
5196 * Play moves forward
\r
5198 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5199 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5200 /* Mouse Wheel is being rolled backward
\r
5201 * Play moves backward
\r
5203 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5204 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5208 case WM_MBUTTONDOWN:
\r
5209 case WM_RBUTTONDOWN:
\r
5212 fromX = fromY = -1;
\r
5213 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5214 dragInfo.start.x = dragInfo.start.y = -1;
\r
5215 dragInfo.from = dragInfo.start;
\r
5216 dragInfo.lastpos = dragInfo.pos;
\r
5217 if (appData.highlightDragging) {
\r
5218 ClearHighlights();
\r
5221 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5222 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5223 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5224 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5225 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5228 DrawPosition(TRUE, NULL);
\r
5230 switch (gameMode) {
\r
5231 case EditPosition:
\r
5232 case IcsExamining:
\r
5233 if (x < 0 || y < 0) break;
\r
5236 if (message == WM_MBUTTONDOWN) {
\r
5237 buttonCount = 3; /* even if system didn't think so */
\r
5238 if (wParam & MK_SHIFT)
\r
5239 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5241 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5242 } else { /* message == WM_RBUTTONDOWN */
\r
5243 /* Just have one menu, on the right button. Windows users don't
\r
5244 think to try the middle one, and sometimes other software steals
\r
5245 it, or it doesn't really exist. */
\r
5246 if(gameInfo.variant != VariantShogi)
\r
5247 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5249 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5252 case IcsPlayingWhite:
\r
5253 case IcsPlayingBlack:
\r
5255 case MachinePlaysWhite:
\r
5256 case MachinePlaysBlack:
\r
5257 if (appData.testLegality &&
\r
5258 gameInfo.variant != VariantBughouse &&
\r
5259 gameInfo.variant != VariantCrazyhouse) break;
\r
5260 if (x < 0 || y < 0) break;
\r
5263 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5264 SetupDropMenu(hmenu);
\r
5265 MenuPopup(hwnd, pt, hmenu, -1);
\r
5276 /* Preprocess messages for buttons in main window */
\r
5278 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5280 int id = GetWindowLong(hwnd, GWL_ID);
\r
5283 for (i=0; i<N_BUTTONS; i++) {
\r
5284 if (buttonDesc[i].id == id) break;
\r
5286 if (i == N_BUTTONS) return 0;
\r
5287 switch (message) {
\r
5292 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5293 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5300 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5303 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5304 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5305 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5306 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5308 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5310 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5311 PopUpMoveDialog((char)wParam);
\r
5317 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5320 /* Process messages for Promotion dialog box */
\r
5322 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5326 switch (message) {
\r
5327 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5328 /* Center the dialog over the application window */
\r
5329 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5330 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5331 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5332 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5333 SW_SHOW : SW_HIDE);
\r
5334 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5335 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5336 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5337 PieceToChar(WhiteAngel) != '~') ||
\r
5338 (PieceToChar(BlackAngel) >= 'A' &&
\r
5339 PieceToChar(BlackAngel) != '~') ) ?
\r
5340 SW_SHOW : SW_HIDE);
\r
5341 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5342 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5343 PieceToChar(WhiteMarshall) != '~') ||
\r
5344 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5345 PieceToChar(BlackMarshall) != '~') ) ?
\r
5346 SW_SHOW : SW_HIDE);
\r
5347 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5348 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5349 gameInfo.variant != VariantShogi ?
\r
5350 SW_SHOW : SW_HIDE);
\r
5351 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5352 gameInfo.variant != VariantShogi ?
\r
5353 SW_SHOW : SW_HIDE);
\r
5354 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5355 gameInfo.variant == VariantShogi ?
\r
5356 SW_SHOW : SW_HIDE);
\r
5357 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5358 gameInfo.variant == VariantShogi ?
\r
5359 SW_SHOW : SW_HIDE);
\r
5360 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5361 gameInfo.variant == VariantSuper ?
\r
5362 SW_SHOW : SW_HIDE);
\r
5365 case WM_COMMAND: /* message: received a command */
\r
5366 switch (LOWORD(wParam)) {
\r
5368 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5369 ClearHighlights();
\r
5370 DrawPosition(FALSE, NULL);
\r
5373 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5376 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5379 promoChar = PieceToChar(BlackRook);
\r
5382 promoChar = PieceToChar(BlackBishop);
\r
5384 case PB_Chancellor:
\r
5385 promoChar = PieceToChar(BlackMarshall);
\r
5387 case PB_Archbishop:
\r
5388 promoChar = PieceToChar(BlackAngel);
\r
5391 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5396 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5397 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5398 only show the popup when we are already sure the move is valid or
\r
5399 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5400 will figure out it is a promotion from the promoChar. */
\r
5401 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5402 if (!appData.highlightLastMove) {
\r
5403 ClearHighlights();
\r
5404 DrawPosition(FALSE, NULL);
\r
5411 /* Pop up promotion dialog */
\r
5413 PromotionPopup(HWND hwnd)
\r
5417 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5418 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5419 hwnd, (DLGPROC)lpProc);
\r
5420 FreeProcInstance(lpProc);
\r
5423 /* Toggle ShowThinking */
\r
5425 ToggleShowThinking()
\r
5427 appData.showThinking = !appData.showThinking;
\r
5428 ShowThinkingEvent();
\r
5432 LoadGameDialog(HWND hwnd, char* title)
\r
5436 char fileTitle[MSG_SIZ];
\r
5437 f = OpenFileDialog(hwnd, "rb", "",
\r
5438 appData.oldSaveStyle ? "gam" : "pgn",
\r
5440 title, &number, fileTitle, NULL);
\r
5442 cmailMsgLoaded = FALSE;
\r
5443 if (number == 0) {
\r
5444 int error = GameListBuild(f);
\r
5446 DisplayError("Cannot build game list", error);
\r
5447 } else if (!ListEmpty(&gameList) &&
\r
5448 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5449 GameListPopUp(f, fileTitle);
\r
5452 GameListDestroy();
\r
5455 LoadGame(f, number, fileTitle, FALSE);
\r
5459 void UpdateICSWidth(HWND hText)
\r
5464 HFONT hfont, hold_font;
\r
5466 // get the text metrics
\r
5467 hdc = GetDC(hText);
\r
5468 hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);
\r
5469 hold_font = SelectObject(hdc, hfont);
\r
5470 GetTextMetrics(hdc, &tm);
\r
5471 SelectObject(hdc, hold_font);
\r
5472 DeleteObject(hfont);
\r
5473 ReleaseDC(hText, hdc);
\r
5475 // get the rectangle
\r
5476 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5478 // update the width
\r
5479 ics_update_width((rc.right-rc.left) / tm.tmAveCharWidth);
\r
5483 ChangedConsoleFont()
\r
5486 CHARRANGE tmpsel, sel;
\r
5487 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5488 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5489 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5492 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5493 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5494 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5495 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5496 * size. This was undocumented in the version of MSVC++ that I had
\r
5497 * when I wrote the code, but is apparently documented now.
\r
5499 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5500 cfmt.bCharSet = f->lf.lfCharSet;
\r
5501 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5502 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5503 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5504 /* Why are the following seemingly needed too? */
\r
5505 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5506 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5507 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5509 tmpsel.cpMax = -1; /*999999?*/
\r
5510 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5511 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5512 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5513 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5515 paraf.cbSize = sizeof(paraf);
\r
5516 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5517 paraf.dxStartIndent = 0;
\r
5518 paraf.dxOffset = WRAP_INDENT;
\r
5519 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5520 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5521 UpdateICSWidth(hText);
\r
5524 /*---------------------------------------------------------------------------*\
\r
5526 * Window Proc for main window
\r
5528 \*---------------------------------------------------------------------------*/
\r
5530 /* Process messages for main window, etc. */
\r
5532 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5535 int wmId, wmEvent;
\r
5539 char fileTitle[MSG_SIZ];
\r
5540 char buf[MSG_SIZ];
\r
5541 static SnapData sd;
\r
5543 switch (message) {
\r
5545 case WM_PAINT: /* message: repaint portion of window */
\r
5549 case WM_ERASEBKGND:
\r
5550 if (IsIconic(hwnd)) {
\r
5551 /* Cheat; change the message */
\r
5552 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5554 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5558 case WM_LBUTTONDOWN:
\r
5559 case WM_MBUTTONDOWN:
\r
5560 case WM_RBUTTONDOWN:
\r
5561 case WM_LBUTTONUP:
\r
5562 case WM_MBUTTONUP:
\r
5563 case WM_RBUTTONUP:
\r
5564 case WM_MOUSEMOVE:
\r
5565 case WM_MOUSEWHEEL:
\r
5566 MouseEvent(hwnd, message, wParam, lParam);
\r
5569 JAWS_KB_NAVIGATION
\r
5573 JAWS_ALT_INTERCEPT
\r
5575 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5576 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5577 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5578 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5580 SendMessage(h, message, wParam, lParam);
\r
5581 } else if(lParam != KF_REPEAT) {
\r
5582 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5583 PopUpMoveDialog((char)wParam);
\r
5584 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5585 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5590 case WM_PALETTECHANGED:
\r
5591 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5593 HDC hdc = GetDC(hwndMain);
\r
5594 SelectPalette(hdc, hPal, TRUE);
\r
5595 nnew = RealizePalette(hdc);
\r
5597 paletteChanged = TRUE;
\r
5598 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5600 ReleaseDC(hwnd, hdc);
\r
5604 case WM_QUERYNEWPALETTE:
\r
5605 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5607 HDC hdc = GetDC(hwndMain);
\r
5608 paletteChanged = FALSE;
\r
5609 SelectPalette(hdc, hPal, FALSE);
\r
5610 nnew = RealizePalette(hdc);
\r
5612 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5614 ReleaseDC(hwnd, hdc);
\r
5619 case WM_COMMAND: /* message: command from application menu */
\r
5620 wmId = LOWORD(wParam);
\r
5621 wmEvent = HIWORD(wParam);
\r
5626 AnalysisPopDown();
\r
5627 SAY("new game enter a move to play against the computer with white");
\r
5630 case IDM_NewGameFRC:
\r
5631 if( NewGameFRC() == 0 ) {
\r
5633 AnalysisPopDown();
\r
5637 case IDM_NewVariant:
\r
5638 NewVariantPopup(hwnd);
\r
5641 case IDM_LoadGame:
\r
5642 LoadGameDialog(hwnd, "Load Game from File");
\r
5645 case IDM_LoadNextGame:
\r
5649 case IDM_LoadPrevGame:
\r
5653 case IDM_ReloadGame:
\r
5657 case IDM_LoadPosition:
\r
5658 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5659 Reset(FALSE, TRUE);
\r
5662 f = OpenFileDialog(hwnd, "rb", "",
\r
5663 appData.oldSaveStyle ? "pos" : "fen",
\r
5665 "Load Position from File", &number, fileTitle, NULL);
\r
5667 LoadPosition(f, number, fileTitle);
\r
5671 case IDM_LoadNextPosition:
\r
5672 ReloadPosition(1);
\r
5675 case IDM_LoadPrevPosition:
\r
5676 ReloadPosition(-1);
\r
5679 case IDM_ReloadPosition:
\r
5680 ReloadPosition(0);
\r
5683 case IDM_SaveGame:
\r
5684 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5685 f = OpenFileDialog(hwnd, "a", defName,
\r
5686 appData.oldSaveStyle ? "gam" : "pgn",
\r
5688 "Save Game to File", NULL, fileTitle, NULL);
\r
5690 SaveGame(f, 0, "");
\r
5694 case IDM_SavePosition:
\r
5695 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5696 f = OpenFileDialog(hwnd, "a", defName,
\r
5697 appData.oldSaveStyle ? "pos" : "fen",
\r
5699 "Save Position to File", NULL, fileTitle, NULL);
\r
5701 SavePosition(f, 0, "");
\r
5705 case IDM_SaveDiagram:
\r
5706 defName = "diagram";
\r
5707 f = OpenFileDialog(hwnd, "wb", defName,
\r
5710 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5716 case IDM_CopyGame:
\r
5717 CopyGameToClipboard();
\r
5720 case IDM_PasteGame:
\r
5721 PasteGameFromClipboard();
\r
5724 case IDM_CopyGameListToClipboard:
\r
5725 CopyGameListToClipboard();
\r
5728 /* [AS] Autodetect FEN or PGN data */
\r
5729 case IDM_PasteAny:
\r
5730 PasteGameOrFENFromClipboard();
\r
5733 /* [AS] Move history */
\r
5734 case IDM_ShowMoveHistory:
\r
5735 if( MoveHistoryIsUp() ) {
\r
5736 MoveHistoryPopDown();
\r
5739 MoveHistoryPopUp();
\r
5743 /* [AS] Eval graph */
\r
5744 case IDM_ShowEvalGraph:
\r
5745 if( EvalGraphIsUp() ) {
\r
5746 EvalGraphPopDown();
\r
5750 SetFocus(hwndMain);
\r
5754 /* [AS] Engine output */
\r
5755 case IDM_ShowEngineOutput:
\r
5756 if( EngineOutputIsUp() ) {
\r
5757 EngineOutputPopDown();
\r
5760 EngineOutputPopUp();
\r
5764 /* [AS] User adjudication */
\r
5765 case IDM_UserAdjudication_White:
\r
5766 UserAdjudicationEvent( +1 );
\r
5769 case IDM_UserAdjudication_Black:
\r
5770 UserAdjudicationEvent( -1 );
\r
5773 case IDM_UserAdjudication_Draw:
\r
5774 UserAdjudicationEvent( 0 );
\r
5777 /* [AS] Game list options dialog */
\r
5778 case IDM_GameListOptions:
\r
5779 GameListOptions();
\r
5786 case IDM_CopyPosition:
\r
5787 CopyFENToClipboard();
\r
5790 case IDM_PastePosition:
\r
5791 PasteFENFromClipboard();
\r
5794 case IDM_MailMove:
\r
5798 case IDM_ReloadCMailMsg:
\r
5799 Reset(TRUE, TRUE);
\r
5800 ReloadCmailMsgEvent(FALSE);
\r
5803 case IDM_Minimize:
\r
5804 ShowWindow(hwnd, SW_MINIMIZE);
\r
5811 case IDM_MachineWhite:
\r
5812 MachineWhiteEvent();
\r
5814 * refresh the tags dialog only if it's visible
\r
5816 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5818 tags = PGNTags(&gameInfo);
\r
5819 TagsPopUp(tags, CmailMsg());
\r
5822 SAY("computer starts playing white");
\r
5825 case IDM_MachineBlack:
\r
5826 MachineBlackEvent();
\r
5828 * refresh the tags dialog only if it's visible
\r
5830 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5832 tags = PGNTags(&gameInfo);
\r
5833 TagsPopUp(tags, CmailMsg());
\r
5836 SAY("computer starts playing black");
\r
5839 case IDM_TwoMachines:
\r
5840 TwoMachinesEvent();
\r
5842 * refresh the tags dialog only if it's visible
\r
5844 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5846 tags = PGNTags(&gameInfo);
\r
5847 TagsPopUp(tags, CmailMsg());
\r
5850 SAY("programs start playing each other");
\r
5853 case IDM_AnalysisMode:
\r
5854 if (!first.analysisSupport) {
\r
5855 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5856 DisplayError(buf, 0);
\r
5858 SAY("analyzing current position");
\r
5859 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5860 if (appData.icsActive) {
\r
5861 if (gameMode != IcsObserving) {
\r
5862 sprintf(buf, "You are not observing a game");
\r
5863 DisplayError(buf, 0);
\r
5864 /* secure check */
\r
5865 if (appData.icsEngineAnalyze) {
\r
5866 if (appData.debugMode)
\r
5867 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5868 ExitAnalyzeMode();
\r
5874 /* if enable, user want disable icsEngineAnalyze */
\r
5875 if (appData.icsEngineAnalyze) {
\r
5876 ExitAnalyzeMode();
\r
5880 appData.icsEngineAnalyze = TRUE;
\r
5881 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5884 if (!appData.showThinking) ToggleShowThinking();
\r
5885 AnalyzeModeEvent();
\r
5889 case IDM_AnalyzeFile:
\r
5890 if (!first.analysisSupport) {
\r
5891 char buf[MSG_SIZ];
\r
5892 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5893 DisplayError(buf, 0);
\r
5895 if (!appData.showThinking) ToggleShowThinking();
\r
5896 AnalyzeFileEvent();
\r
5897 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5898 AnalysisPeriodicEvent(1);
\r
5902 case IDM_IcsClient:
\r
5906 case IDM_EditGame:
\r
5911 case IDM_EditPosition:
\r
5912 EditPositionEvent();
\r
5913 SAY("to set up a position type a FEN");
\r
5916 case IDM_Training:
\r
5920 case IDM_ShowGameList:
\r
5921 ShowGameListProc();
\r
5924 case IDM_EditTags:
\r
5928 case IDM_EditComment:
\r
5929 if (commentDialogUp && editComment) {
\r
5932 EditCommentEvent();
\r
5952 case IDM_CallFlag:
\r
5972 case IDM_StopObserving:
\r
5973 StopObservingEvent();
\r
5976 case IDM_StopExamining:
\r
5977 StopExaminingEvent();
\r
5980 case IDM_TypeInMove:
\r
5981 PopUpMoveDialog('\000');
\r
5984 case IDM_TypeInName:
\r
5985 PopUpNameDialog('\000');
\r
5988 case IDM_Backward:
\r
5990 SetFocus(hwndMain);
\r
5997 SetFocus(hwndMain);
\r
6002 SetFocus(hwndMain);
\r
6007 SetFocus(hwndMain);
\r
6014 case IDM_TruncateGame:
\r
6015 TruncateGameEvent();
\r
6022 case IDM_RetractMove:
\r
6023 RetractMoveEvent();
\r
6026 case IDM_FlipView:
\r
6027 flipView = !flipView;
\r
6028 DrawPosition(FALSE, NULL);
\r
6031 case IDM_FlipClock:
\r
6032 flipClock = !flipClock;
\r
6033 DisplayBothClocks();
\r
6034 DrawPosition(FALSE, NULL);
\r
6037 case IDM_MuteSounds:
\r
6038 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6039 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6040 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6043 case IDM_GeneralOptions:
\r
6044 GeneralOptionsPopup(hwnd);
\r
6045 DrawPosition(TRUE, NULL);
\r
6048 case IDM_BoardOptions:
\r
6049 BoardOptionsPopup(hwnd);
\r
6052 case IDM_EnginePlayOptions:
\r
6053 EnginePlayOptionsPopup(hwnd);
\r
6056 case IDM_Engine1Options:
\r
6057 EngineOptionsPopup(hwnd, &first);
\r
6060 case IDM_Engine2Options:
\r
6061 EngineOptionsPopup(hwnd, &second);
\r
6064 case IDM_OptionsUCI:
\r
6065 UciOptionsPopup(hwnd);
\r
6068 case IDM_IcsOptions:
\r
6069 IcsOptionsPopup(hwnd);
\r
6073 FontsOptionsPopup(hwnd);
\r
6077 SoundOptionsPopup(hwnd);
\r
6080 case IDM_CommPort:
\r
6081 CommPortOptionsPopup(hwnd);
\r
6084 case IDM_LoadOptions:
\r
6085 LoadOptionsPopup(hwnd);
\r
6088 case IDM_SaveOptions:
\r
6089 SaveOptionsPopup(hwnd);
\r
6092 case IDM_TimeControl:
\r
6093 TimeControlOptionsPopup(hwnd);
\r
6096 case IDM_SaveSettings:
\r
6097 SaveSettings(settingsFileName);
\r
6100 case IDM_SaveSettingsOnExit:
\r
6101 saveSettingsOnExit = !saveSettingsOnExit;
\r
6102 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6103 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6104 MF_CHECKED : MF_UNCHECKED));
\r
6115 case IDM_AboutGame:
\r
6120 appData.debugMode = !appData.debugMode;
\r
6121 if (appData.debugMode) {
\r
6122 char dir[MSG_SIZ];
\r
6123 GetCurrentDirectory(MSG_SIZ, dir);
\r
6124 SetCurrentDirectory(installDir);
\r
6125 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6126 SetCurrentDirectory(dir);
\r
6127 setbuf(debugFP, NULL);
\r
6134 case IDM_HELPCONTENTS:
\r
6135 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6136 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6137 MessageBox (GetFocus(),
\r
6138 "Unable to activate help",
\r
6139 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6143 case IDM_HELPSEARCH:
\r
6144 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6145 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6146 MessageBox (GetFocus(),
\r
6147 "Unable to activate help",
\r
6148 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6152 case IDM_HELPHELP:
\r
6153 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6154 MessageBox (GetFocus(),
\r
6155 "Unable to activate help",
\r
6156 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6161 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6163 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6164 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6165 FreeProcInstance(lpProc);
\r
6168 case IDM_DirectCommand1:
\r
6169 AskQuestionEvent("Direct Command",
\r
6170 "Send to chess program:", "", "1");
\r
6172 case IDM_DirectCommand2:
\r
6173 AskQuestionEvent("Direct Command",
\r
6174 "Send to second chess program:", "", "2");
\r
6177 case EP_WhitePawn:
\r
6178 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6179 fromX = fromY = -1;
\r
6182 case EP_WhiteKnight:
\r
6183 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6184 fromX = fromY = -1;
\r
6187 case EP_WhiteBishop:
\r
6188 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6189 fromX = fromY = -1;
\r
6192 case EP_WhiteRook:
\r
6193 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6194 fromX = fromY = -1;
\r
6197 case EP_WhiteQueen:
\r
6198 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6199 fromX = fromY = -1;
\r
6202 case EP_WhiteFerz:
\r
6203 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6204 fromX = fromY = -1;
\r
6207 case EP_WhiteWazir:
\r
6208 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6209 fromX = fromY = -1;
\r
6212 case EP_WhiteAlfil:
\r
6213 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6214 fromX = fromY = -1;
\r
6217 case EP_WhiteCannon:
\r
6218 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6219 fromX = fromY = -1;
\r
6222 case EP_WhiteCardinal:
\r
6223 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6224 fromX = fromY = -1;
\r
6227 case EP_WhiteMarshall:
\r
6228 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6229 fromX = fromY = -1;
\r
6232 case EP_WhiteKing:
\r
6233 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6234 fromX = fromY = -1;
\r
6237 case EP_BlackPawn:
\r
6238 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6239 fromX = fromY = -1;
\r
6242 case EP_BlackKnight:
\r
6243 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6244 fromX = fromY = -1;
\r
6247 case EP_BlackBishop:
\r
6248 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6249 fromX = fromY = -1;
\r
6252 case EP_BlackRook:
\r
6253 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6254 fromX = fromY = -1;
\r
6257 case EP_BlackQueen:
\r
6258 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6259 fromX = fromY = -1;
\r
6262 case EP_BlackFerz:
\r
6263 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6264 fromX = fromY = -1;
\r
6267 case EP_BlackWazir:
\r
6268 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6269 fromX = fromY = -1;
\r
6272 case EP_BlackAlfil:
\r
6273 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6274 fromX = fromY = -1;
\r
6277 case EP_BlackCannon:
\r
6278 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6279 fromX = fromY = -1;
\r
6282 case EP_BlackCardinal:
\r
6283 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6284 fromX = fromY = -1;
\r
6287 case EP_BlackMarshall:
\r
6288 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6289 fromX = fromY = -1;
\r
6292 case EP_BlackKing:
\r
6293 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6294 fromX = fromY = -1;
\r
6297 case EP_EmptySquare:
\r
6298 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6299 fromX = fromY = -1;
\r
6302 case EP_ClearBoard:
\r
6303 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6304 fromX = fromY = -1;
\r
6308 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6309 fromX = fromY = -1;
\r
6313 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6314 fromX = fromY = -1;
\r
6318 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6319 fromX = fromY = -1;
\r
6323 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6324 fromX = fromY = -1;
\r
6328 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6329 fromX = fromY = -1;
\r
6333 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6334 fromX = fromY = -1;
\r
6338 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6339 fromX = fromY = -1;
\r
6343 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6344 fromX = fromY = -1;
\r
6348 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6349 fromX = fromY = -1;
\r
6353 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6359 case CLOCK_TIMER_ID:
\r
6360 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6361 clockTimerEvent = 0;
\r
6362 DecrementClocks(); /* call into back end */
\r
6364 case LOAD_GAME_TIMER_ID:
\r
6365 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6366 loadGameTimerEvent = 0;
\r
6367 AutoPlayGameLoop(); /* call into back end */
\r
6369 case ANALYSIS_TIMER_ID:
\r
6370 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6371 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6372 AnalysisPeriodicEvent(0);
\r
6374 KillTimer(hwnd, analysisTimerEvent);
\r
6375 analysisTimerEvent = 0;
\r
6378 case DELAYED_TIMER_ID:
\r
6379 KillTimer(hwnd, delayedTimerEvent);
\r
6380 delayedTimerEvent = 0;
\r
6381 delayedTimerCallback();
\r
6386 case WM_USER_Input:
\r
6387 InputEvent(hwnd, message, wParam, lParam);
\r
6390 /* [AS] Also move "attached" child windows */
\r
6391 case WM_WINDOWPOSCHANGING:
\r
6393 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6394 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6396 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6397 /* Window is moving */
\r
6400 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6401 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6402 rcMain.right = boardX + winWidth;
\r
6403 rcMain.top = boardY;
\r
6404 rcMain.bottom = boardY + winHeight;
\r
6406 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6407 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6408 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6409 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6410 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6417 /* [AS] Snapping */
\r
6418 case WM_ENTERSIZEMOVE:
\r
6419 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6420 if (hwnd == hwndMain) {
\r
6421 doingSizing = TRUE;
\r
6424 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6428 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6429 if (hwnd == hwndMain) {
\r
6430 lastSizing = wParam;
\r
6435 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6436 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6438 case WM_EXITSIZEMOVE:
\r
6439 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6440 if (hwnd == hwndMain) {
\r
6442 doingSizing = FALSE;
\r
6443 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6444 GetClientRect(hwnd, &client);
\r
6445 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6447 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6449 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6452 case WM_DESTROY: /* message: window being destroyed */
\r
6453 PostQuitMessage(0);
\r
6457 if (hwnd == hwndMain) {
\r
6462 default: /* Passes it on if unprocessed */
\r
6463 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6468 /*---------------------------------------------------------------------------*\
\r
6470 * Misc utility routines
\r
6472 \*---------------------------------------------------------------------------*/
\r
6475 * Decent random number generator, at least not as bad as Windows
\r
6476 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6478 unsigned int randstate;
\r
6483 randstate = randstate * 1664525 + 1013904223;
\r
6484 return (int) randstate & 0x7fffffff;
\r
6488 mysrandom(unsigned int seed)
\r
6495 * returns TRUE if user selects a different color, FALSE otherwise
\r
6499 ChangeColor(HWND hwnd, COLORREF *which)
\r
6501 static BOOL firstTime = TRUE;
\r
6502 static DWORD customColors[16];
\r
6504 COLORREF newcolor;
\r
6509 /* Make initial colors in use available as custom colors */
\r
6510 /* Should we put the compiled-in defaults here instead? */
\r
6512 customColors[i++] = lightSquareColor & 0xffffff;
\r
6513 customColors[i++] = darkSquareColor & 0xffffff;
\r
6514 customColors[i++] = whitePieceColor & 0xffffff;
\r
6515 customColors[i++] = blackPieceColor & 0xffffff;
\r
6516 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6517 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6519 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6520 customColors[i++] = textAttribs[ccl].color;
\r
6522 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6523 firstTime = FALSE;
\r
6526 cc.lStructSize = sizeof(cc);
\r
6527 cc.hwndOwner = hwnd;
\r
6528 cc.hInstance = NULL;
\r
6529 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6530 cc.lpCustColors = (LPDWORD) customColors;
\r
6531 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6533 if (!ChooseColor(&cc)) return FALSE;
\r
6535 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6536 if (newcolor == *which) return FALSE;
\r
6537 *which = newcolor;
\r
6541 InitDrawingColors();
\r
6542 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6547 MyLoadSound(MySound *ms)
\r
6553 if (ms->data) free(ms->data);
\r
6556 switch (ms->name[0]) {
\r
6562 /* System sound from Control Panel. Don't preload here. */
\r
6566 if (ms->name[1] == NULLCHAR) {
\r
6567 /* "!" alone = silence */
\r
6570 /* Builtin wave resource. Error if not found. */
\r
6571 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6572 if (h == NULL) break;
\r
6573 ms->data = (void *)LoadResource(hInst, h);
\r
6574 if (h == NULL) break;
\r
6579 /* .wav file. Error if not found. */
\r
6580 f = fopen(ms->name, "rb");
\r
6581 if (f == NULL) break;
\r
6582 if (fstat(fileno(f), &st) < 0) break;
\r
6583 ms->data = malloc(st.st_size);
\r
6584 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6590 char buf[MSG_SIZ];
\r
6591 sprintf(buf, "Error loading sound %s", ms->name);
\r
6592 DisplayError(buf, GetLastError());
\r
6598 MyPlaySound(MySound *ms)
\r
6600 BOOLEAN ok = FALSE;
\r
6602 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6603 switch (ms->name[0]) {
\r
6605 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6610 /* System sound from Control Panel (deprecated feature).
\r
6611 "$" alone or an unset sound name gets default beep (still in use). */
\r
6612 if (ms->name[1]) {
\r
6613 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6615 if (!ok) ok = MessageBeep(MB_OK);
\r
6618 /* Builtin wave resource, or "!" alone for silence */
\r
6619 if (ms->name[1]) {
\r
6620 if (ms->data == NULL) return FALSE;
\r
6621 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6627 /* .wav file. Error if not found. */
\r
6628 if (ms->data == NULL) return FALSE;
\r
6629 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6632 /* Don't print an error: this can happen innocently if the sound driver
\r
6633 is busy; for instance, if another instance of WinBoard is playing
\r
6634 a sound at about the same time. */
\r
6640 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6643 OPENFILENAME *ofn;
\r
6644 static UINT *number; /* gross that this is static */
\r
6646 switch (message) {
\r
6647 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6648 /* Center the dialog over the application window */
\r
6649 ofn = (OPENFILENAME *) lParam;
\r
6650 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6651 number = (UINT *) ofn->lCustData;
\r
6652 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6656 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6657 return FALSE; /* Allow for further processing */
\r
6660 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6661 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6663 return FALSE; /* Allow for further processing */
\r
6669 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6671 static UINT *number;
\r
6672 OPENFILENAME *ofname;
\r
6675 case WM_INITDIALOG:
\r
6676 ofname = (OPENFILENAME *)lParam;
\r
6677 number = (UINT *)(ofname->lCustData);
\r
6680 ofnot = (OFNOTIFY *)lParam;
\r
6681 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6682 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6691 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6692 char *nameFilt, char *dlgTitle, UINT *number,
\r
6693 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6695 OPENFILENAME openFileName;
\r
6696 char buf1[MSG_SIZ];
\r
6699 if (fileName == NULL) fileName = buf1;
\r
6700 if (defName == NULL) {
\r
6701 strcpy(fileName, "*.");
\r
6702 strcat(fileName, defExt);
\r
6704 strcpy(fileName, defName);
\r
6706 if (fileTitle) strcpy(fileTitle, "");
\r
6707 if (number) *number = 0;
\r
6709 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6710 openFileName.hwndOwner = hwnd;
\r
6711 openFileName.hInstance = (HANDLE) hInst;
\r
6712 openFileName.lpstrFilter = nameFilt;
\r
6713 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6714 openFileName.nMaxCustFilter = 0L;
\r
6715 openFileName.nFilterIndex = 1L;
\r
6716 openFileName.lpstrFile = fileName;
\r
6717 openFileName.nMaxFile = MSG_SIZ;
\r
6718 openFileName.lpstrFileTitle = fileTitle;
\r
6719 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6720 openFileName.lpstrInitialDir = NULL;
\r
6721 openFileName.lpstrTitle = dlgTitle;
\r
6722 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6723 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6724 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6725 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6726 openFileName.nFileOffset = 0;
\r
6727 openFileName.nFileExtension = 0;
\r
6728 openFileName.lpstrDefExt = defExt;
\r
6729 openFileName.lCustData = (LONG) number;
\r
6730 openFileName.lpfnHook = oldDialog ?
\r
6731 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6732 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6734 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6735 GetOpenFileName(&openFileName)) {
\r
6736 /* open the file */
\r
6737 f = fopen(openFileName.lpstrFile, write);
\r
6739 MessageBox(hwnd, "File open failed", NULL,
\r
6740 MB_OK|MB_ICONEXCLAMATION);
\r
6744 int err = CommDlgExtendedError();
\r
6745 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6754 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6756 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6759 * Get the first pop-up menu in the menu template. This is the
\r
6760 * menu that TrackPopupMenu displays.
\r
6762 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6764 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6767 * TrackPopup uses screen coordinates, so convert the
\r
6768 * coordinates of the mouse click to screen coordinates.
\r
6770 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6772 /* Draw and track the floating pop-up menu. */
\r
6773 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6774 pt.x, pt.y, 0, hwnd, NULL);
\r
6776 /* Destroy the menu.*/
\r
6777 DestroyMenu(hmenu);
\r
6782 int sizeX, sizeY, newSizeX, newSizeY;
\r
6784 } ResizeEditPlusButtonsClosure;
\r
6787 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6789 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6793 if (hChild == cl->hText) return TRUE;
\r
6794 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6795 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6796 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6797 ScreenToClient(cl->hDlg, &pt);
\r
6798 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6799 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6803 /* Resize a dialog that has a (rich) edit field filling most of
\r
6804 the top, with a row of buttons below */
\r
6806 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6809 int newTextHeight, newTextWidth;
\r
6810 ResizeEditPlusButtonsClosure cl;
\r
6812 /*if (IsIconic(hDlg)) return;*/
\r
6813 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6815 cl.hdwp = BeginDeferWindowPos(8);
\r
6817 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6818 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6819 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6820 if (newTextHeight < 0) {
\r
6821 newSizeY += -newTextHeight;
\r
6822 newTextHeight = 0;
\r
6824 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6825 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6831 cl.newSizeX = newSizeX;
\r
6832 cl.newSizeY = newSizeY;
\r
6833 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6835 EndDeferWindowPos(cl.hdwp);
\r
6838 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6840 RECT rChild, rParent;
\r
6841 int wChild, hChild, wParent, hParent;
\r
6842 int wScreen, hScreen, xNew, yNew;
\r
6845 /* Get the Height and Width of the child window */
\r
6846 GetWindowRect (hwndChild, &rChild);
\r
6847 wChild = rChild.right - rChild.left;
\r
6848 hChild = rChild.bottom - rChild.top;
\r
6850 /* Get the Height and Width of the parent window */
\r
6851 GetWindowRect (hwndParent, &rParent);
\r
6852 wParent = rParent.right - rParent.left;
\r
6853 hParent = rParent.bottom - rParent.top;
\r
6855 /* Get the display limits */
\r
6856 hdc = GetDC (hwndChild);
\r
6857 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6858 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6859 ReleaseDC(hwndChild, hdc);
\r
6861 /* Calculate new X position, then adjust for screen */
\r
6862 xNew = rParent.left + ((wParent - wChild) /2);
\r
6865 } else if ((xNew+wChild) > wScreen) {
\r
6866 xNew = wScreen - wChild;
\r
6869 /* Calculate new Y position, then adjust for screen */
\r
6871 yNew = rParent.top + ((hParent - hChild) /2);
\r
6874 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6879 } else if ((yNew+hChild) > hScreen) {
\r
6880 yNew = hScreen - hChild;
\r
6883 /* Set it, and return */
\r
6884 return SetWindowPos (hwndChild, NULL,
\r
6885 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6888 /* Center one window over another */
\r
6889 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6891 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6894 /*---------------------------------------------------------------------------*\
\r
6896 * Startup Dialog functions
\r
6898 \*---------------------------------------------------------------------------*/
\r
6900 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6902 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6904 while (*cd != NULL) {
\r
6905 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6911 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6913 char buf1[ARG_MAX];
\r
6916 if (str[0] == '@') {
\r
6917 FILE* f = fopen(str + 1, "r");
\r
6919 DisplayFatalError(str + 1, errno, 2);
\r
6922 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6924 buf1[len] = NULLCHAR;
\r
6928 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6931 char buf[MSG_SIZ];
\r
6932 char *end = strchr(str, '\n');
\r
6933 if (end == NULL) return;
\r
6934 memcpy(buf, str, end - str);
\r
6935 buf[end - str] = NULLCHAR;
\r
6936 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6942 SetStartupDialogEnables(HWND hDlg)
\r
6944 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6945 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6946 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6947 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6948 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6949 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6950 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6951 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6952 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6953 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6954 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6955 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6956 IsDlgButtonChecked(hDlg, OPT_View));
\r
6960 QuoteForFilename(char *filename)
\r
6962 int dquote, space;
\r
6963 dquote = strchr(filename, '"') != NULL;
\r
6964 space = strchr(filename, ' ') != NULL;
\r
6965 if (dquote || space) {
\r
6977 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6979 char buf[MSG_SIZ];
\r
6982 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6983 q = QuoteForFilename(nthcp);
\r
6984 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6985 if (*nthdir != NULLCHAR) {
\r
6986 q = QuoteForFilename(nthdir);
\r
6987 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6989 if (*nthcp == NULLCHAR) {
\r
6990 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6991 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6992 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6993 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6998 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7000 char buf[MSG_SIZ];
\r
7004 switch (message) {
\r
7005 case WM_INITDIALOG:
\r
7006 /* Center the dialog */
\r
7007 CenterWindow (hDlg, GetDesktopWindow());
\r
7008 /* Initialize the dialog items */
\r
7009 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7010 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7011 firstChessProgramNames);
\r
7012 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7013 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7014 secondChessProgramNames);
\r
7015 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7016 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7017 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7018 if (*appData.icsHelper != NULLCHAR) {
\r
7019 char *q = QuoteForFilename(appData.icsHelper);
\r
7020 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7022 if (*appData.icsHost == NULLCHAR) {
\r
7023 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7024 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7025 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7026 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7027 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7030 if (appData.icsActive) {
\r
7031 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7033 else if (appData.noChessProgram) {
\r
7034 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7037 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7040 SetStartupDialogEnables(hDlg);
\r
7044 switch (LOWORD(wParam)) {
\r
7046 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7047 strcpy(buf, "/fcp=");
\r
7048 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7050 ParseArgs(StringGet, &p);
\r
7051 strcpy(buf, "/scp=");
\r
7052 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7054 ParseArgs(StringGet, &p);
\r
7055 appData.noChessProgram = FALSE;
\r
7056 appData.icsActive = FALSE;
\r
7057 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7058 strcpy(buf, "/ics /icshost=");
\r
7059 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7061 ParseArgs(StringGet, &p);
\r
7062 if (appData.zippyPlay) {
\r
7063 strcpy(buf, "/fcp=");
\r
7064 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7066 ParseArgs(StringGet, &p);
\r
7068 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7069 appData.noChessProgram = TRUE;
\r
7070 appData.icsActive = FALSE;
\r
7072 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7073 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7076 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7077 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7079 ParseArgs(StringGet, &p);
\r
7081 EndDialog(hDlg, TRUE);
\r
7088 case IDM_HELPCONTENTS:
\r
7089 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7090 MessageBox (GetFocus(),
\r
7091 "Unable to activate help",
\r
7092 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7097 SetStartupDialogEnables(hDlg);
\r
7105 /*---------------------------------------------------------------------------*\
\r
7107 * About box dialog functions
\r
7109 \*---------------------------------------------------------------------------*/
\r
7111 /* Process messages for "About" dialog box */
\r
7113 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7115 switch (message) {
\r
7116 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7117 /* Center the dialog over the application window */
\r
7118 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7119 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7123 case WM_COMMAND: /* message: received a command */
\r
7124 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7125 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7126 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7134 /*---------------------------------------------------------------------------*\
\r
7136 * Comment Dialog functions
\r
7138 \*---------------------------------------------------------------------------*/
\r
7141 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7143 static HANDLE hwndText = NULL;
\r
7144 int len, newSizeX, newSizeY, flags;
\r
7145 static int sizeX, sizeY;
\r
7150 switch (message) {
\r
7151 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7152 /* Initialize the dialog items */
\r
7153 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7154 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7155 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7156 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7157 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7158 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7159 SetWindowText(hDlg, commentTitle);
\r
7160 if (editComment) {
\r
7161 SetFocus(hwndText);
\r
7163 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7165 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7166 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7167 MAKELPARAM(FALSE, 0));
\r
7168 /* Size and position the dialog */
\r
7169 if (!commentDialog) {
\r
7170 commentDialog = hDlg;
\r
7171 flags = SWP_NOZORDER;
\r
7172 GetClientRect(hDlg, &rect);
\r
7173 sizeX = rect.right;
\r
7174 sizeY = rect.bottom;
\r
7175 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7176 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7177 WINDOWPLACEMENT wp;
\r
7178 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7179 wp.length = sizeof(WINDOWPLACEMENT);
\r
7181 wp.showCmd = SW_SHOW;
\r
7182 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7183 wp.rcNormalPosition.left = commentX;
\r
7184 wp.rcNormalPosition.right = commentX + commentW;
\r
7185 wp.rcNormalPosition.top = commentY;
\r
7186 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7187 SetWindowPlacement(hDlg, &wp);
\r
7189 GetClientRect(hDlg, &rect);
\r
7190 newSizeX = rect.right;
\r
7191 newSizeY = rect.bottom;
\r
7192 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7193 newSizeX, newSizeY);
\r
7200 case WM_COMMAND: /* message: received a command */
\r
7201 switch (LOWORD(wParam)) {
\r
7203 if (editComment) {
\r
7205 /* Read changed options from the dialog box */
\r
7206 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7207 len = GetWindowTextLength(hwndText);
\r
7208 str = (char *) malloc(len + 1);
\r
7209 GetWindowText(hwndText, str, len + 1);
\r
7218 ReplaceComment(commentIndex, str);
\r
7225 case OPT_CancelComment:
\r
7229 case OPT_ClearComment:
\r
7230 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7233 case OPT_EditComment:
\r
7234 EditCommentEvent();
\r
7243 newSizeX = LOWORD(lParam);
\r
7244 newSizeY = HIWORD(lParam);
\r
7245 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7250 case WM_GETMINMAXINFO:
\r
7251 /* Prevent resizing window too small */
\r
7252 mmi = (MINMAXINFO *) lParam;
\r
7253 mmi->ptMinTrackSize.x = 100;
\r
7254 mmi->ptMinTrackSize.y = 100;
\r
7261 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7266 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7268 if (str == NULL) str = "";
\r
7269 p = (char *) malloc(2 * strlen(str) + 2);
\r
7272 if (*str == '\n') *q++ = '\r';
\r
7276 if (commentText != NULL) free(commentText);
\r
7278 commentIndex = index;
\r
7279 commentTitle = title;
\r
7281 editComment = edit;
\r
7283 if (commentDialog) {
\r
7284 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7285 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7287 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7288 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7289 hwndMain, (DLGPROC)lpProc);
\r
7290 FreeProcInstance(lpProc);
\r
7292 commentDialogUp = TRUE;
\r
7296 /*---------------------------------------------------------------------------*\
\r
7298 * Type-in move dialog functions
\r
7300 \*---------------------------------------------------------------------------*/
\r
7303 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7305 char move[MSG_SIZ];
\r
7307 ChessMove moveType;
\r
7308 int fromX, fromY, toX, toY;
\r
7311 switch (message) {
\r
7312 case WM_INITDIALOG:
\r
7313 move[0] = (char) lParam;
\r
7314 move[1] = NULLCHAR;
\r
7315 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7316 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7317 SetWindowText(hInput, move);
\r
7319 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7323 switch (LOWORD(wParam)) {
\r
7325 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7326 { int n; Board board;
\r
7328 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7329 EditPositionPasteFEN(move);
\r
7330 EndDialog(hDlg, TRUE);
\r
7333 // [HGM] movenum: allow move number to be typed in any mode
\r
7334 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7335 currentMove = 2*n-1;
\r
7336 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7337 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7338 EndDialog(hDlg, TRUE);
\r
7339 DrawPosition(TRUE, boards[currentMove]);
\r
7340 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7341 else DisplayMessage("", "");
\r
7345 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7346 gameMode != Training) {
\r
7347 DisplayMoveError("Displayed move is not current");
\r
7349 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7350 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7351 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7352 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7353 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7354 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7355 if (gameMode != Training)
\r
7356 forwardMostMove = currentMove;
\r
7357 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7359 DisplayMoveError("Could not parse move");
\r
7362 EndDialog(hDlg, TRUE);
\r
7365 EndDialog(hDlg, FALSE);
\r
7376 PopUpMoveDialog(char firstchar)
\r
7380 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7381 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7382 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7383 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7384 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7385 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7386 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7387 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7388 gameMode == Training) {
\r
7389 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7390 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7391 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7392 FreeProcInstance(lpProc);
\r
7396 /*---------------------------------------------------------------------------*\
\r
7398 * Type-in name dialog functions
\r
7400 \*---------------------------------------------------------------------------*/
\r
7403 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7405 char move[MSG_SIZ];
\r
7408 switch (message) {
\r
7409 case WM_INITDIALOG:
\r
7410 move[0] = (char) lParam;
\r
7411 move[1] = NULLCHAR;
\r
7412 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7413 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7414 SetWindowText(hInput, move);
\r
7416 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7420 switch (LOWORD(wParam)) {
\r
7422 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7423 appData.userName = strdup(move);
\r
7426 EndDialog(hDlg, TRUE);
\r
7429 EndDialog(hDlg, FALSE);
\r
7440 PopUpNameDialog(char firstchar)
\r
7444 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7445 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7446 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7447 FreeProcInstance(lpProc);
\r
7450 /*---------------------------------------------------------------------------*\
\r
7454 \*---------------------------------------------------------------------------*/
\r
7456 /* Nonmodal error box */
\r
7457 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7458 WPARAM wParam, LPARAM lParam);
\r
7461 ErrorPopUp(char *title, char *content)
\r
7465 BOOLEAN modal = hwndMain == NULL;
\r
7483 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7484 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7487 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7489 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7490 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7491 hwndMain, (DLGPROC)lpProc);
\r
7492 FreeProcInstance(lpProc);
\r
7499 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7500 if (errorDialog == NULL) return;
\r
7501 DestroyWindow(errorDialog);
\r
7502 errorDialog = NULL;
\r
7506 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7511 switch (message) {
\r
7512 case WM_INITDIALOG:
\r
7513 GetWindowRect(hDlg, &rChild);
\r
7516 SetWindowPos(hDlg, NULL, rChild.left,
\r
7517 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7518 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7522 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7523 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7524 and it doesn't work when you resize the dialog.
\r
7525 For now, just give it a default position.
\r
7527 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7529 errorDialog = hDlg;
\r
7530 SetWindowText(hDlg, errorTitle);
\r
7531 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7532 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7536 switch (LOWORD(wParam)) {
\r
7539 if (errorDialog == hDlg) errorDialog = NULL;
\r
7540 DestroyWindow(hDlg);
\r
7552 HWND gothicDialog = NULL;
\r
7555 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7559 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7561 switch (message) {
\r
7562 case WM_INITDIALOG:
\r
7563 GetWindowRect(hDlg, &rChild);
\r
7565 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7569 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7570 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7571 and it doesn't work when you resize the dialog.
\r
7572 For now, just give it a default position.
\r
7574 gothicDialog = hDlg;
\r
7575 SetWindowText(hDlg, errorTitle);
\r
7576 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7577 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7581 switch (LOWORD(wParam)) {
\r
7584 if (errorDialog == hDlg) errorDialog = NULL;
\r
7585 DestroyWindow(hDlg);
\r
7597 GothicPopUp(char *title, VariantClass variant)
\r
7600 static char *lastTitle;
\r
7602 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7603 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7605 if(lastTitle != title && gothicDialog != NULL) {
\r
7606 DestroyWindow(gothicDialog);
\r
7607 gothicDialog = NULL;
\r
7609 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7610 title = lastTitle;
\r
7611 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7612 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7613 hwndMain, (DLGPROC)lpProc);
\r
7614 FreeProcInstance(lpProc);
\r
7619 /*---------------------------------------------------------------------------*\
\r
7621 * Ics Interaction console functions
\r
7623 \*---------------------------------------------------------------------------*/
\r
7625 #define HISTORY_SIZE 64
\r
7626 static char *history[HISTORY_SIZE];
\r
7627 int histIn = 0, histP = 0;
\r
7630 SaveInHistory(char *cmd)
\r
7632 if (history[histIn] != NULL) {
\r
7633 free(history[histIn]);
\r
7634 history[histIn] = NULL;
\r
7636 if (*cmd == NULLCHAR) return;
\r
7637 history[histIn] = StrSave(cmd);
\r
7638 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7639 if (history[histIn] != NULL) {
\r
7640 free(history[histIn]);
\r
7641 history[histIn] = NULL;
\r
7647 PrevInHistory(char *cmd)
\r
7650 if (histP == histIn) {
\r
7651 if (history[histIn] != NULL) free(history[histIn]);
\r
7652 history[histIn] = StrSave(cmd);
\r
7654 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7655 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7657 return history[histP];
\r
7663 if (histP == histIn) return NULL;
\r
7664 histP = (histP + 1) % HISTORY_SIZE;
\r
7665 return history[histP];
\r
7672 BOOLEAN immediate;
\r
7673 } IcsTextMenuEntry;
\r
7674 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7675 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7678 ParseIcsTextMenu(char *icsTextMenuString)
\r
7681 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7682 char *p = icsTextMenuString;
\r
7683 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7686 if (e->command != NULL) {
\r
7688 e->command = NULL;
\r
7692 e = icsTextMenuEntry;
\r
7693 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7694 if (*p == ';' || *p == '\n') {
\r
7695 e->item = strdup("-");
\r
7696 e->command = NULL;
\r
7698 } else if (*p == '-') {
\r
7699 e->item = strdup("-");
\r
7700 e->command = NULL;
\r
7704 char *q, *r, *s, *t;
\r
7706 q = strchr(p, ',');
\r
7707 if (q == NULL) break;
\r
7709 r = strchr(q + 1, ',');
\r
7710 if (r == NULL) break;
\r
7712 s = strchr(r + 1, ',');
\r
7713 if (s == NULL) break;
\r
7716 t = strchr(s + 1, c);
\r
7719 t = strchr(s + 1, c);
\r
7721 if (t != NULL) *t = NULLCHAR;
\r
7722 e->item = strdup(p);
\r
7723 e->command = strdup(q + 1);
\r
7724 e->getname = *(r + 1) != '0';
\r
7725 e->immediate = *(s + 1) != '0';
\r
7729 if (t == NULL) break;
\r
7738 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7742 hmenu = LoadMenu(hInst, "TextMenu");
\r
7743 h = GetSubMenu(hmenu, 0);
\r
7745 if (strcmp(e->item, "-") == 0) {
\r
7746 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7748 if (e->item[0] == '|') {
\r
7749 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7750 IDM_CommandX + i, &e->item[1]);
\r
7752 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7761 WNDPROC consoleTextWindowProc;
\r
7764 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7766 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7767 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7771 SetWindowText(hInput, command);
\r
7773 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7775 sel.cpMin = 999999;
\r
7776 sel.cpMax = 999999;
\r
7777 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7782 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7783 if (sel.cpMin == sel.cpMax) {
\r
7784 /* Expand to surrounding word */
\r
7787 tr.chrg.cpMax = sel.cpMin;
\r
7788 tr.chrg.cpMin = --sel.cpMin;
\r
7789 if (sel.cpMin < 0) break;
\r
7790 tr.lpstrText = name;
\r
7791 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7792 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7796 tr.chrg.cpMin = sel.cpMax;
\r
7797 tr.chrg.cpMax = ++sel.cpMax;
\r
7798 tr.lpstrText = name;
\r
7799 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7800 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7803 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7804 MessageBeep(MB_ICONEXCLAMATION);
\r
7808 tr.lpstrText = name;
\r
7809 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7811 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7812 MessageBeep(MB_ICONEXCLAMATION);
\r
7815 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7818 sprintf(buf, "%s %s", command, name);
\r
7819 SetWindowText(hInput, buf);
\r
7820 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7822 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7823 SetWindowText(hInput, buf);
\r
7824 sel.cpMin = 999999;
\r
7825 sel.cpMax = 999999;
\r
7826 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7832 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7837 switch (message) {
\r
7839 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7842 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7845 sel.cpMin = 999999;
\r
7846 sel.cpMax = 999999;
\r
7847 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7848 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7853 if(wParam != '\022') {
\r
7854 if (wParam == '\t') {
\r
7855 if (GetKeyState(VK_SHIFT) < 0) {
\r
7857 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7858 if (buttonDesc[0].hwnd) {
\r
7859 SetFocus(buttonDesc[0].hwnd);
\r
7861 SetFocus(hwndMain);
\r
7865 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7868 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7869 JAWS_DELETE( SetFocus(hInput); )
\r
7870 SendMessage(hInput, message, wParam, lParam);
\r
7873 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7874 case WM_RBUTTONUP:
\r
7875 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7876 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7877 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7880 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7881 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7882 if (sel.cpMin == sel.cpMax) {
\r
7883 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7884 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7886 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7887 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7889 pt.x = LOWORD(lParam);
\r
7890 pt.y = HIWORD(lParam);
\r
7891 MenuPopup(hwnd, pt, hmenu, -1);
\r
7895 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7897 return SendMessage(hInput, message, wParam, lParam);
\r
7898 case WM_MBUTTONDOWN:
\r
7899 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7900 case WM_RBUTTONDOWN:
\r
7901 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7902 /* Move selection here if it was empty */
\r
7904 pt.x = LOWORD(lParam);
\r
7905 pt.y = HIWORD(lParam);
\r
7906 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7907 if (sel.cpMin == sel.cpMax) {
\r
7908 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7909 sel.cpMax = sel.cpMin;
\r
7910 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7912 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7916 switch (LOWORD(wParam)) {
\r
7917 case IDM_QuickPaste:
\r
7919 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7920 if (sel.cpMin == sel.cpMax) {
\r
7921 MessageBeep(MB_ICONEXCLAMATION);
\r
7924 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7925 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7926 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7931 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7934 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7937 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7941 int i = LOWORD(wParam) - IDM_CommandX;
\r
7942 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7943 icsTextMenuEntry[i].command != NULL) {
\r
7944 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7945 icsTextMenuEntry[i].getname,
\r
7946 icsTextMenuEntry[i].immediate);
\r
7954 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7957 WNDPROC consoleInputWindowProc;
\r
7960 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7962 char buf[MSG_SIZ];
\r
7964 static BOOL sendNextChar = FALSE;
\r
7965 static BOOL quoteNextChar = FALSE;
\r
7966 InputSource *is = consoleInputSource;
\r
7970 switch (message) {
\r
7972 if (!appData.localLineEditing || sendNextChar) {
\r
7973 is->buf[0] = (CHAR) wParam;
\r
7975 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7976 sendNextChar = FALSE;
\r
7979 if (quoteNextChar) {
\r
7980 buf[0] = (char) wParam;
\r
7981 buf[1] = NULLCHAR;
\r
7982 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7983 quoteNextChar = FALSE;
\r
7987 case '\r': /* Enter key */
\r
7988 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7989 if (consoleEcho) SaveInHistory(is->buf);
\r
7990 is->buf[is->count++] = '\n';
\r
7991 is->buf[is->count] = NULLCHAR;
\r
7992 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7993 if (consoleEcho) {
\r
7994 ConsoleOutput(is->buf, is->count, TRUE);
\r
7995 } else if (appData.localLineEditing) {
\r
7996 ConsoleOutput("\n", 1, TRUE);
\r
7999 case '\033': /* Escape key */
\r
8000 SetWindowText(hwnd, "");
\r
8001 cf.cbSize = sizeof(CHARFORMAT);
\r
8002 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8003 if (consoleEcho) {
\r
8004 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8006 cf.crTextColor = COLOR_ECHOOFF;
\r
8008 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8009 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8011 case '\t': /* Tab key */
\r
8012 if (GetKeyState(VK_SHIFT) < 0) {
\r
8014 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8017 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8018 if (buttonDesc[0].hwnd) {
\r
8019 SetFocus(buttonDesc[0].hwnd);
\r
8021 SetFocus(hwndMain);
\r
8025 case '\023': /* Ctrl+S */
\r
8026 sendNextChar = TRUE;
\r
8028 case '\021': /* Ctrl+Q */
\r
8029 quoteNextChar = TRUE;
\r
8039 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8040 p = PrevInHistory(buf);
\r
8042 SetWindowText(hwnd, p);
\r
8043 sel.cpMin = 999999;
\r
8044 sel.cpMax = 999999;
\r
8045 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8050 p = NextInHistory();
\r
8052 SetWindowText(hwnd, p);
\r
8053 sel.cpMin = 999999;
\r
8054 sel.cpMax = 999999;
\r
8055 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8061 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8065 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8069 case WM_MBUTTONDOWN:
\r
8070 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8071 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8073 case WM_RBUTTONUP:
\r
8074 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8075 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8076 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8080 hmenu = LoadMenu(hInst, "InputMenu");
\r
8081 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8082 if (sel.cpMin == sel.cpMax) {
\r
8083 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8084 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8086 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8087 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8089 pt.x = LOWORD(lParam);
\r
8090 pt.y = HIWORD(lParam);
\r
8091 MenuPopup(hwnd, pt, hmenu, -1);
\r
8095 switch (LOWORD(wParam)) {
\r
8097 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8099 case IDM_SelectAll:
\r
8101 sel.cpMax = -1; /*999999?*/
\r
8102 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8105 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8108 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8111 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8116 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8119 #define CO_MAX 100000
\r
8120 #define CO_TRIM 1000
\r
8123 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8125 static SnapData sd;
\r
8126 HWND hText, hInput;
\r
8128 static int sizeX, sizeY;
\r
8129 int newSizeX, newSizeY;
\r
8133 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8134 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8136 switch (message) {
\r
8138 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8140 ENLINK *pLink = (ENLINK*)lParam;
\r
8141 if (pLink->msg == WM_LBUTTONUP)
\r
8145 tr.chrg = pLink->chrg;
\r
8146 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8147 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8148 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8149 free(tr.lpstrText);
\r
8153 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8154 hwndConsole = hDlg;
\r
8156 consoleTextWindowProc = (WNDPROC)
\r
8157 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8158 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8159 consoleInputWindowProc = (WNDPROC)
\r
8160 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8161 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8162 Colorize(ColorNormal, TRUE);
\r
8163 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8164 ChangedConsoleFont();
\r
8165 GetClientRect(hDlg, &rect);
\r
8166 sizeX = rect.right;
\r
8167 sizeY = rect.bottom;
\r
8168 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8169 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8170 WINDOWPLACEMENT wp;
\r
8171 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8172 wp.length = sizeof(WINDOWPLACEMENT);
\r
8174 wp.showCmd = SW_SHOW;
\r
8175 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8176 wp.rcNormalPosition.left = wpConsole.x;
\r
8177 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8178 wp.rcNormalPosition.top = wpConsole.y;
\r
8179 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8180 SetWindowPlacement(hDlg, &wp);
\r
8183 // [HGM] Chessknight's change 2004-07-13
\r
8184 else { /* Determine Defaults */
\r
8185 WINDOWPLACEMENT wp;
\r
8186 wpConsole.x = winWidth + 1;
\r
8187 wpConsole.y = boardY;
\r
8188 wpConsole.width = screenWidth - winWidth;
\r
8189 wpConsole.height = winHeight;
\r
8190 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8191 wp.length = sizeof(WINDOWPLACEMENT);
\r
8193 wp.showCmd = SW_SHOW;
\r
8194 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8195 wp.rcNormalPosition.left = wpConsole.x;
\r
8196 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8197 wp.rcNormalPosition.top = wpConsole.y;
\r
8198 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8199 SetWindowPlacement(hDlg, &wp);
\r
8202 // Allow hText to highlight URLs and send notifications on them
\r
8203 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8204 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8205 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8219 if (IsIconic(hDlg)) break;
\r
8220 newSizeX = LOWORD(lParam);
\r
8221 newSizeY = HIWORD(lParam);
\r
8222 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8223 RECT rectText, rectInput;
\r
8225 int newTextHeight, newTextWidth;
\r
8226 GetWindowRect(hText, &rectText);
\r
8227 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8228 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8229 if (newTextHeight < 0) {
\r
8230 newSizeY += -newTextHeight;
\r
8231 newTextHeight = 0;
\r
8233 SetWindowPos(hText, NULL, 0, 0,
\r
8234 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8235 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8236 pt.x = rectInput.left;
\r
8237 pt.y = rectInput.top + newSizeY - sizeY;
\r
8238 ScreenToClient(hDlg, &pt);
\r
8239 SetWindowPos(hInput, NULL,
\r
8240 pt.x, pt.y, /* needs client coords */
\r
8241 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8242 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8248 case WM_GETMINMAXINFO:
\r
8249 /* Prevent resizing window too small */
\r
8250 mmi = (MINMAXINFO *) lParam;
\r
8251 mmi->ptMinTrackSize.x = 100;
\r
8252 mmi->ptMinTrackSize.y = 100;
\r
8255 /* [AS] Snapping */
\r
8256 case WM_ENTERSIZEMOVE:
\r
8257 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8260 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8263 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8265 case WM_EXITSIZEMOVE:
\r
8266 UpdateICSWidth(hText);
\r
8267 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8270 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8278 if (hwndConsole) return;
\r
8279 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8280 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8285 ConsoleOutput(char* data, int length, int forceVisible)
\r
8290 char buf[CO_MAX+1];
\r
8293 static int delayLF = 0;
\r
8294 CHARRANGE savesel, sel;
\r
8296 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8304 while (length--) {
\r
8312 } else if (*p == '\007') {
\r
8313 MyPlaySound(&sounds[(int)SoundBell]);
\r
8320 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8321 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8322 /* Save current selection */
\r
8323 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8324 exlen = GetWindowTextLength(hText);
\r
8325 /* Find out whether current end of text is visible */
\r
8326 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8327 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8328 /* Trim existing text if it's too long */
\r
8329 if (exlen + (q - buf) > CO_MAX) {
\r
8330 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8333 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8334 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8336 savesel.cpMin -= trim;
\r
8337 savesel.cpMax -= trim;
\r
8338 if (exlen < 0) exlen = 0;
\r
8339 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8340 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8342 /* Append the new text */
\r
8343 sel.cpMin = exlen;
\r
8344 sel.cpMax = exlen;
\r
8345 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8346 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8347 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8348 if (forceVisible || exlen == 0 ||
\r
8349 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8350 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8351 /* Scroll to make new end of text visible if old end of text
\r
8352 was visible or new text is an echo of user typein */
\r
8353 sel.cpMin = 9999999;
\r
8354 sel.cpMax = 9999999;
\r
8355 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8356 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8357 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8358 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8360 if (savesel.cpMax == exlen || forceVisible) {
\r
8361 /* Move insert point to new end of text if it was at the old
\r
8362 end of text or if the new text is an echo of user typein */
\r
8363 sel.cpMin = 9999999;
\r
8364 sel.cpMax = 9999999;
\r
8365 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8367 /* Restore previous selection */
\r
8368 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8370 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8377 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8381 COLORREF oldFg, oldBg;
\r
8385 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8387 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8388 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8389 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8392 rect.right = x + squareSize;
\r
8394 rect.bottom = y + squareSize;
\r
8397 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8398 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8399 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8400 &rect, str, strlen(str), NULL);
\r
8402 (void) SetTextColor(hdc, oldFg);
\r
8403 (void) SetBkColor(hdc, oldBg);
\r
8404 (void) SelectObject(hdc, oldFont);
\r
8408 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8409 RECT *rect, char *color, char *flagFell)
\r
8413 COLORREF oldFg, oldBg;
\r
8416 if (appData.clockMode) {
\r
8418 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8420 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8427 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8428 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8430 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8431 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8433 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8437 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8438 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8439 rect, str, strlen(str), NULL);
\r
8440 if(logoHeight > 0 && appData.clockMode) {
\r
8442 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8443 r.top = rect->top + logoHeight/2;
\r
8444 r.left = rect->left;
\r
8445 r.right = rect->right;
\r
8446 r.bottom = rect->bottom;
\r
8447 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8448 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8449 &r, str, strlen(str), NULL);
\r
8451 (void) SetTextColor(hdc, oldFg);
\r
8452 (void) SetBkColor(hdc, oldBg);
\r
8453 (void) SelectObject(hdc, oldFont);
\r
8458 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8464 if( count <= 0 ) {
\r
8465 if (appData.debugMode) {
\r
8466 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8469 return ERROR_INVALID_USER_BUFFER;
\r
8472 ResetEvent(ovl->hEvent);
\r
8473 ovl->Offset = ovl->OffsetHigh = 0;
\r
8474 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8478 err = GetLastError();
\r
8479 if (err == ERROR_IO_PENDING) {
\r
8480 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8484 err = GetLastError();
\r
8491 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8496 ResetEvent(ovl->hEvent);
\r
8497 ovl->Offset = ovl->OffsetHigh = 0;
\r
8498 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8502 err = GetLastError();
\r
8503 if (err == ERROR_IO_PENDING) {
\r
8504 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8508 err = GetLastError();
\r
8514 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8515 void CheckForInputBufferFull( InputSource * is )
\r
8517 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8518 /* Look for end of line */
\r
8519 char * p = is->buf;
\r
8521 while( p < is->next && *p != '\n' ) {
\r
8525 if( p >= is->next ) {
\r
8526 if (appData.debugMode) {
\r
8527 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8530 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8531 is->count = (DWORD) -1;
\r
8532 is->next = is->buf;
\r
8538 InputThread(LPVOID arg)
\r
8543 is = (InputSource *) arg;
\r
8544 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8545 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8546 while (is->hThread != NULL) {
\r
8547 is->error = DoReadFile(is->hFile, is->next,
\r
8548 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8549 &is->count, &ovl);
\r
8550 if (is->error == NO_ERROR) {
\r
8551 is->next += is->count;
\r
8553 if (is->error == ERROR_BROKEN_PIPE) {
\r
8554 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8557 is->count = (DWORD) -1;
\r
8558 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8563 CheckForInputBufferFull( is );
\r
8565 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8567 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8569 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8572 CloseHandle(ovl.hEvent);
\r
8573 CloseHandle(is->hFile);
\r
8575 if (appData.debugMode) {
\r
8576 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8583 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8585 NonOvlInputThread(LPVOID arg)
\r
8592 is = (InputSource *) arg;
\r
8593 while (is->hThread != NULL) {
\r
8594 is->error = ReadFile(is->hFile, is->next,
\r
8595 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8596 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8597 if (is->error == NO_ERROR) {
\r
8598 /* Change CRLF to LF */
\r
8599 if (is->next > is->buf) {
\r
8601 i = is->count + 1;
\r
8609 if (prev == '\r' && *p == '\n') {
\r
8621 if (is->error == ERROR_BROKEN_PIPE) {
\r
8622 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8625 is->count = (DWORD) -1;
\r
8629 CheckForInputBufferFull( is );
\r
8631 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8633 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8635 if (is->count < 0) break; /* Quit on error */
\r
8637 CloseHandle(is->hFile);
\r
8642 SocketInputThread(LPVOID arg)
\r
8646 is = (InputSource *) arg;
\r
8647 while (is->hThread != NULL) {
\r
8648 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8649 if ((int)is->count == SOCKET_ERROR) {
\r
8650 is->count = (DWORD) -1;
\r
8651 is->error = WSAGetLastError();
\r
8653 is->error = NO_ERROR;
\r
8654 is->next += is->count;
\r
8655 if (is->count == 0 && is->second == is) {
\r
8656 /* End of file on stderr; quit with no message */
\r
8660 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8662 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8664 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8670 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8674 is = (InputSource *) lParam;
\r
8675 if (is->lineByLine) {
\r
8676 /* Feed in lines one by one */
\r
8677 char *p = is->buf;
\r
8679 while (q < is->next) {
\r
8680 if (*q++ == '\n') {
\r
8681 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8686 /* Move any partial line to the start of the buffer */
\r
8688 while (p < is->next) {
\r
8693 if (is->error != NO_ERROR || is->count == 0) {
\r
8694 /* Notify backend of the error. Note: If there was a partial
\r
8695 line at the end, it is not flushed through. */
\r
8696 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8699 /* Feed in the whole chunk of input at once */
\r
8700 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8701 is->next = is->buf;
\r
8705 /*---------------------------------------------------------------------------*\
\r
8707 * Menu enables. Used when setting various modes.
\r
8709 \*---------------------------------------------------------------------------*/
\r
8717 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8719 while (enab->item > 0) {
\r
8720 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8725 Enables gnuEnables[] = {
\r
8726 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8727 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8728 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8729 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8730 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8731 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8732 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8733 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8734 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8735 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8739 Enables icsEnables[] = {
\r
8740 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8742 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8744 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8745 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8746 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8747 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8748 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8756 Enables zippyEnables[] = {
\r
8757 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8758 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8759 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8764 Enables ncpEnables[] = {
\r
8765 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8766 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8767 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8768 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8769 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8770 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8771 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8772 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8773 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8774 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8783 Enables trainingOnEnables[] = {
\r
8784 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8795 Enables trainingOffEnables[] = {
\r
8796 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8797 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8798 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8799 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8800 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8801 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8802 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8803 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8807 /* These modify either ncpEnables or gnuEnables */
\r
8808 Enables cmailEnables[] = {
\r
8809 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8810 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8811 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8812 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8814 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8819 Enables machineThinkingEnables[] = {
\r
8820 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8838 Enables userThinkingEnables[] = {
\r
8839 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8840 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8841 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8842 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8844 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8845 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8853 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8857 /*---------------------------------------------------------------------------*\
\r
8859 * Front-end interface functions exported by XBoard.
\r
8860 * Functions appear in same order as prototypes in frontend.h.
\r
8862 \*---------------------------------------------------------------------------*/
\r
8866 static UINT prevChecked = 0;
\r
8867 static int prevPausing = 0;
\r
8870 if (pausing != prevPausing) {
\r
8871 prevPausing = pausing;
\r
8872 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8873 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8874 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8877 switch (gameMode) {
\r
8878 case BeginningOfGame:
\r
8879 if (appData.icsActive)
\r
8880 nowChecked = IDM_IcsClient;
\r
8881 else if (appData.noChessProgram)
\r
8882 nowChecked = IDM_EditGame;
\r
8884 nowChecked = IDM_MachineBlack;
\r
8886 case MachinePlaysBlack:
\r
8887 nowChecked = IDM_MachineBlack;
\r
8889 case MachinePlaysWhite:
\r
8890 nowChecked = IDM_MachineWhite;
\r
8892 case TwoMachinesPlay:
\r
8893 nowChecked = IDM_TwoMachines;
\r
8896 nowChecked = IDM_AnalysisMode;
\r
8899 nowChecked = IDM_AnalyzeFile;
\r
8902 nowChecked = IDM_EditGame;
\r
8904 case PlayFromGameFile:
\r
8905 nowChecked = IDM_LoadGame;
\r
8907 case EditPosition:
\r
8908 nowChecked = IDM_EditPosition;
\r
8911 nowChecked = IDM_Training;
\r
8913 case IcsPlayingWhite:
\r
8914 case IcsPlayingBlack:
\r
8915 case IcsObserving:
\r
8917 nowChecked = IDM_IcsClient;
\r
8924 if (prevChecked != 0)
\r
8925 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8926 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8927 if (nowChecked != 0)
\r
8928 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8929 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8931 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8932 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8933 MF_BYCOMMAND|MF_ENABLED);
\r
8935 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8936 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8939 prevChecked = nowChecked;
\r
8941 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8942 if (appData.icsActive) {
\r
8943 if (appData.icsEngineAnalyze) {
\r
8944 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8945 MF_BYCOMMAND|MF_CHECKED);
\r
8947 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8948 MF_BYCOMMAND|MF_UNCHECKED);
\r
8956 HMENU hmenu = GetMenu(hwndMain);
\r
8957 SetMenuEnables(hmenu, icsEnables);
\r
8958 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8959 MF_BYPOSITION|MF_ENABLED);
\r
8961 if (appData.zippyPlay) {
\r
8962 SetMenuEnables(hmenu, zippyEnables);
\r
8963 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8964 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8965 MF_BYCOMMAND|MF_ENABLED);
\r
8973 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8979 HMENU hmenu = GetMenu(hwndMain);
\r
8980 SetMenuEnables(hmenu, ncpEnables);
\r
8981 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8982 MF_BYPOSITION|MF_GRAYED);
\r
8983 DrawMenuBar(hwndMain);
\r
8989 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8993 SetTrainingModeOn()
\r
8996 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8997 for (i = 0; i < N_BUTTONS; i++) {
\r
8998 if (buttonDesc[i].hwnd != NULL)
\r
8999 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9004 VOID SetTrainingModeOff()
\r
9007 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9008 for (i = 0; i < N_BUTTONS; i++) {
\r
9009 if (buttonDesc[i].hwnd != NULL)
\r
9010 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9016 SetUserThinkingEnables()
\r
9018 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9022 SetMachineThinkingEnables()
\r
9024 HMENU hMenu = GetMenu(hwndMain);
\r
9025 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9027 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9029 if (gameMode == MachinePlaysBlack) {
\r
9030 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9031 } else if (gameMode == MachinePlaysWhite) {
\r
9032 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9033 } else if (gameMode == TwoMachinesPlay) {
\r
9034 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9040 DisplayTitle(char *str)
\r
9042 char title[MSG_SIZ], *host;
\r
9043 if (str[0] != NULLCHAR) {
\r
9044 strcpy(title, str);
\r
9045 } else if (appData.icsActive) {
\r
9046 if (appData.icsCommPort[0] != NULLCHAR)
\r
9049 host = appData.icsHost;
\r
9050 sprintf(title, "%s: %s", szTitle, host);
\r
9051 } else if (appData.noChessProgram) {
\r
9052 strcpy(title, szTitle);
\r
9054 strcpy(title, szTitle);
\r
9055 strcat(title, ": ");
\r
9056 strcat(title, first.tidy);
\r
9058 SetWindowText(hwndMain, title);
\r
9063 DisplayMessage(char *str1, char *str2)
\r
9067 int remain = MESSAGE_TEXT_MAX - 1;
\r
9070 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9071 messageText[0] = NULLCHAR;
\r
9073 len = strlen(str1);
\r
9074 if (len > remain) len = remain;
\r
9075 strncpy(messageText, str1, len);
\r
9076 messageText[len] = NULLCHAR;
\r
9079 if (*str2 && remain >= 2) {
\r
9081 strcat(messageText, " ");
\r
9084 len = strlen(str2);
\r
9085 if (len > remain) len = remain;
\r
9086 strncat(messageText, str2, len);
\r
9088 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9090 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9094 hdc = GetDC(hwndMain);
\r
9095 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9096 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9097 &messageRect, messageText, strlen(messageText), NULL);
\r
9098 (void) SelectObject(hdc, oldFont);
\r
9099 (void) ReleaseDC(hwndMain, hdc);
\r
9103 DisplayError(char *str, int error)
\r
9105 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9111 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9112 NULL, error, LANG_NEUTRAL,
\r
9113 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9115 sprintf(buf, "%s:\n%s", str, buf2);
\r
9117 ErrorMap *em = errmap;
\r
9118 while (em->err != 0 && em->err != error) em++;
\r
9119 if (em->err != 0) {
\r
9120 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9122 sprintf(buf, "%s:\nError code %d", str, error);
\r
9127 ErrorPopUp("Error", buf);
\r
9132 DisplayMoveError(char *str)
\r
9134 fromX = fromY = -1;
\r
9135 ClearHighlights();
\r
9136 DrawPosition(FALSE, NULL);
\r
9137 if (appData.popupMoveErrors) {
\r
9138 ErrorPopUp("Error", str);
\r
9140 DisplayMessage(str, "");
\r
9141 moveErrorMessageUp = TRUE;
\r
9146 DisplayFatalError(char *str, int error, int exitStatus)
\r
9148 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9150 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9153 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9154 NULL, error, LANG_NEUTRAL,
\r
9155 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9157 sprintf(buf, "%s:\n%s", str, buf2);
\r
9159 ErrorMap *em = errmap;
\r
9160 while (em->err != 0 && em->err != error) em++;
\r
9161 if (em->err != 0) {
\r
9162 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9164 sprintf(buf, "%s:\nError code %d", str, error);
\r
9169 if (appData.debugMode) {
\r
9170 fprintf(debugFP, "%s: %s\n", label, str);
\r
9172 if (appData.popupExitMessage) {
\r
9173 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9174 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9176 ExitEvent(exitStatus);
\r
9181 DisplayInformation(char *str)
\r
9183 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9188 DisplayNote(char *str)
\r
9190 ErrorPopUp("Note", str);
\r
9195 char *title, *question, *replyPrefix;
\r
9200 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9202 static QuestionParams *qp;
\r
9203 char reply[MSG_SIZ];
\r
9206 switch (message) {
\r
9207 case WM_INITDIALOG:
\r
9208 qp = (QuestionParams *) lParam;
\r
9209 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9210 SetWindowText(hDlg, qp->title);
\r
9211 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9212 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9216 switch (LOWORD(wParam)) {
\r
9218 strcpy(reply, qp->replyPrefix);
\r
9219 if (*reply) strcat(reply, " ");
\r
9220 len = strlen(reply);
\r
9221 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9222 strcat(reply, "\n");
\r
9223 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9224 EndDialog(hDlg, TRUE);
\r
9225 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9228 EndDialog(hDlg, FALSE);
\r
9239 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9241 QuestionParams qp;
\r
9245 qp.question = question;
\r
9246 qp.replyPrefix = replyPrefix;
\r
9248 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9249 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9250 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9251 FreeProcInstance(lpProc);
\r
9254 /* [AS] Pick FRC position */
\r
9255 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9257 static int * lpIndexFRC;
\r
9263 case WM_INITDIALOG:
\r
9264 lpIndexFRC = (int *) lParam;
\r
9266 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9268 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9269 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9270 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9271 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9276 switch( LOWORD(wParam) ) {
\r
9278 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9279 EndDialog( hDlg, 0 );
\r
9280 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9283 EndDialog( hDlg, 1 );
\r
9285 case IDC_NFG_Edit:
\r
9286 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9287 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9289 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9292 case IDC_NFG_Random:
\r
9293 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9294 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9307 int index = appData.defaultFrcPosition;
\r
9308 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9310 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9312 if( result == 0 ) {
\r
9313 appData.defaultFrcPosition = index;
\r
9319 /* [AS] Game list options */
\r
9325 static GLT_Item GLT_ItemInfo[] = {
\r
9326 { GLT_EVENT, "Event" },
\r
9327 { GLT_SITE, "Site" },
\r
9328 { GLT_DATE, "Date" },
\r
9329 { GLT_ROUND, "Round" },
\r
9330 { GLT_PLAYERS, "Players" },
\r
9331 { GLT_RESULT, "Result" },
\r
9332 { GLT_WHITE_ELO, "White Rating" },
\r
9333 { GLT_BLACK_ELO, "Black Rating" },
\r
9334 { GLT_TIME_CONTROL,"Time Control" },
\r
9335 { GLT_VARIANT, "Variant" },
\r
9336 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9337 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9341 const char * GLT_FindItem( char id )
\r
9343 const char * result = 0;
\r
9345 GLT_Item * list = GLT_ItemInfo;
\r
9347 while( list->id != 0 ) {
\r
9348 if( list->id == id ) {
\r
9349 result = list->name;
\r
9359 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9361 const char * name = GLT_FindItem( id );
\r
9364 if( index >= 0 ) {
\r
9365 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9368 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9373 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9377 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9380 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9384 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9386 pc = GLT_ALL_TAGS;
\r
9389 if( strchr( tags, *pc ) == 0 ) {
\r
9390 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9395 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9398 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9400 char result = '\0';
\r
9403 GLT_Item * list = GLT_ItemInfo;
\r
9405 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9406 while( list->id != 0 ) {
\r
9407 if( strcmp( list->name, name ) == 0 ) {
\r
9408 result = list->id;
\r
9419 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9421 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9422 int idx2 = idx1 + delta;
\r
9423 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9425 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9428 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9429 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9430 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9431 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9435 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9437 static char glt[64];
\r
9438 static char * lpUserGLT;
\r
9442 case WM_INITDIALOG:
\r
9443 lpUserGLT = (char *) lParam;
\r
9445 strcpy( glt, lpUserGLT );
\r
9447 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9449 /* Initialize list */
\r
9450 GLT_TagsToList( hDlg, glt );
\r
9452 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9457 switch( LOWORD(wParam) ) {
\r
9460 char * pc = lpUserGLT;
\r
9462 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9466 id = GLT_ListItemToTag( hDlg, idx );
\r
9470 } while( id != '\0' );
\r
9472 EndDialog( hDlg, 0 );
\r
9475 EndDialog( hDlg, 1 );
\r
9478 case IDC_GLT_Default:
\r
9479 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9480 GLT_TagsToList( hDlg, glt );
\r
9483 case IDC_GLT_Restore:
\r
9484 strcpy( glt, lpUserGLT );
\r
9485 GLT_TagsToList( hDlg, glt );
\r
9489 GLT_MoveSelection( hDlg, -1 );
\r
9492 case IDC_GLT_Down:
\r
9493 GLT_MoveSelection( hDlg, +1 );
\r
9503 int GameListOptions()
\r
9507 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9509 strcpy( glt, appData.gameListTags );
\r
9511 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9513 if( result == 0 ) {
\r
9514 /* [AS] Memory leak here! */
\r
9515 appData.gameListTags = strdup( glt );
\r
9523 DisplayIcsInteractionTitle(char *str)
\r
9525 char consoleTitle[MSG_SIZ];
\r
9527 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9528 SetWindowText(hwndConsole, consoleTitle);
\r
9532 DrawPosition(int fullRedraw, Board board)
\r
9534 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9537 void NotifyFrontendLogin()
\r
9540 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9546 fromX = fromY = -1;
\r
9547 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9548 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9549 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9550 dragInfo.lastpos = dragInfo.pos;
\r
9551 dragInfo.start.x = dragInfo.start.y = -1;
\r
9552 dragInfo.from = dragInfo.start;
\r
9554 DrawPosition(TRUE, NULL);
\r
9560 CommentPopUp(char *title, char *str)
\r
9562 HWND hwnd = GetActiveWindow();
\r
9563 EitherCommentPopUp(0, title, str, FALSE);
\r
9565 SetActiveWindow(hwnd);
\r
9569 CommentPopDown(void)
\r
9571 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9572 if (commentDialog) {
\r
9573 ShowWindow(commentDialog, SW_HIDE);
\r
9575 commentDialogUp = FALSE;
\r
9579 EditCommentPopUp(int index, char *title, char *str)
\r
9581 EitherCommentPopUp(index, title, str, TRUE);
\r
9588 MyPlaySound(&sounds[(int)SoundMove]);
\r
9591 VOID PlayIcsWinSound()
\r
9593 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9596 VOID PlayIcsLossSound()
\r
9598 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9601 VOID PlayIcsDrawSound()
\r
9603 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9606 VOID PlayIcsUnfinishedSound()
\r
9608 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9614 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9622 consoleEcho = TRUE;
\r
9623 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9624 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9625 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9634 consoleEcho = FALSE;
\r
9635 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9636 /* This works OK: set text and background both to the same color */
\r
9638 cf.crTextColor = COLOR_ECHOOFF;
\r
9639 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9640 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9643 /* No Raw()...? */
\r
9645 void Colorize(ColorClass cc, int continuation)
\r
9647 currentColorClass = cc;
\r
9648 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9649 consoleCF.crTextColor = textAttribs[cc].color;
\r
9650 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9651 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9657 static char buf[MSG_SIZ];
\r
9658 DWORD bufsiz = MSG_SIZ;
\r
9660 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9661 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9663 if (!GetUserName(buf, &bufsiz)) {
\r
9664 /*DisplayError("Error getting user name", GetLastError());*/
\r
9665 strcpy(buf, "User");
\r
9673 static char buf[MSG_SIZ];
\r
9674 DWORD bufsiz = MSG_SIZ;
\r
9676 if (!GetComputerName(buf, &bufsiz)) {
\r
9677 /*DisplayError("Error getting host name", GetLastError());*/
\r
9678 strcpy(buf, "Unknown");
\r
9685 ClockTimerRunning()
\r
9687 return clockTimerEvent != 0;
\r
9693 if (clockTimerEvent == 0) return FALSE;
\r
9694 KillTimer(hwndMain, clockTimerEvent);
\r
9695 clockTimerEvent = 0;
\r
9700 StartClockTimer(long millisec)
\r
9702 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9703 (UINT) millisec, NULL);
\r
9707 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9710 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9712 if(appData.noGUI) return;
\r
9713 hdc = GetDC(hwndMain);
\r
9714 if (!IsIconic(hwndMain)) {
\r
9715 DisplayAClock(hdc, timeRemaining, highlight,
\r
9716 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9718 if (highlight && iconCurrent == iconBlack) {
\r
9719 iconCurrent = iconWhite;
\r
9720 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9721 if (IsIconic(hwndMain)) {
\r
9722 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9725 (void) ReleaseDC(hwndMain, hdc);
\r
9727 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9731 DisplayBlackClock(long timeRemaining, int highlight)
\r
9734 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9736 if(appData.noGUI) return;
\r
9737 hdc = GetDC(hwndMain);
\r
9738 if (!IsIconic(hwndMain)) {
\r
9739 DisplayAClock(hdc, timeRemaining, highlight,
\r
9740 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9742 if (highlight && iconCurrent == iconWhite) {
\r
9743 iconCurrent = iconBlack;
\r
9744 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9745 if (IsIconic(hwndMain)) {
\r
9746 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9749 (void) ReleaseDC(hwndMain, hdc);
\r
9751 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9756 LoadGameTimerRunning()
\r
9758 return loadGameTimerEvent != 0;
\r
9762 StopLoadGameTimer()
\r
9764 if (loadGameTimerEvent == 0) return FALSE;
\r
9765 KillTimer(hwndMain, loadGameTimerEvent);
\r
9766 loadGameTimerEvent = 0;
\r
9771 StartLoadGameTimer(long millisec)
\r
9773 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9774 (UINT) millisec, NULL);
\r
9782 char fileTitle[MSG_SIZ];
\r
9784 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9785 f = OpenFileDialog(hwndMain, "a", defName,
\r
9786 appData.oldSaveStyle ? "gam" : "pgn",
\r
9788 "Save Game to File", NULL, fileTitle, NULL);
\r
9790 SaveGame(f, 0, "");
\r
9797 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9799 if (delayedTimerEvent != 0) {
\r
9800 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9801 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9803 KillTimer(hwndMain, delayedTimerEvent);
\r
9804 delayedTimerEvent = 0;
\r
9805 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9806 delayedTimerCallback();
\r
9808 delayedTimerCallback = cb;
\r
9809 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9810 (UINT) millisec, NULL);
\r
9813 DelayedEventCallback
\r
9816 if (delayedTimerEvent) {
\r
9817 return delayedTimerCallback;
\r
9824 CancelDelayedEvent()
\r
9826 if (delayedTimerEvent) {
\r
9827 KillTimer(hwndMain, delayedTimerEvent);
\r
9828 delayedTimerEvent = 0;
\r
9832 DWORD GetWin32Priority(int nice)
\r
9833 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9835 REALTIME_PRIORITY_CLASS 0x00000100
\r
9836 HIGH_PRIORITY_CLASS 0x00000080
\r
9837 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9838 NORMAL_PRIORITY_CLASS 0x00000020
\r
9839 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9840 IDLE_PRIORITY_CLASS 0x00000040
\r
9842 if (nice < -15) return 0x00000080;
\r
9843 if (nice < 0) return 0x00008000;
\r
9844 if (nice == 0) return 0x00000020;
\r
9845 if (nice < 15) return 0x00004000;
\r
9846 return 0x00000040;
\r
9849 /* Start a child process running the given program.
\r
9850 The process's standard output can be read from "from", and its
\r
9851 standard input can be written to "to".
\r
9852 Exit with fatal error if anything goes wrong.
\r
9853 Returns an opaque pointer that can be used to destroy the process
\r
9857 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9859 #define BUFSIZE 4096
\r
9861 HANDLE hChildStdinRd, hChildStdinWr,
\r
9862 hChildStdoutRd, hChildStdoutWr;
\r
9863 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9864 SECURITY_ATTRIBUTES saAttr;
\r
9866 PROCESS_INFORMATION piProcInfo;
\r
9867 STARTUPINFO siStartInfo;
\r
9869 char buf[MSG_SIZ];
\r
9872 if (appData.debugMode) {
\r
9873 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9878 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9879 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9880 saAttr.bInheritHandle = TRUE;
\r
9881 saAttr.lpSecurityDescriptor = NULL;
\r
9884 * The steps for redirecting child's STDOUT:
\r
9885 * 1. Create anonymous pipe to be STDOUT for child.
\r
9886 * 2. Create a noninheritable duplicate of read handle,
\r
9887 * and close the inheritable read handle.
\r
9890 /* Create a pipe for the child's STDOUT. */
\r
9891 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9892 return GetLastError();
\r
9895 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9896 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9897 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9898 FALSE, /* not inherited */
\r
9899 DUPLICATE_SAME_ACCESS);
\r
9901 return GetLastError();
\r
9903 CloseHandle(hChildStdoutRd);
\r
9906 * The steps for redirecting child's STDIN:
\r
9907 * 1. Create anonymous pipe to be STDIN for child.
\r
9908 * 2. Create a noninheritable duplicate of write handle,
\r
9909 * and close the inheritable write handle.
\r
9912 /* Create a pipe for the child's STDIN. */
\r
9913 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9914 return GetLastError();
\r
9917 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9918 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9919 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9920 FALSE, /* not inherited */
\r
9921 DUPLICATE_SAME_ACCESS);
\r
9923 return GetLastError();
\r
9925 CloseHandle(hChildStdinWr);
\r
9927 /* Arrange to (1) look in dir for the child .exe file, and
\r
9928 * (2) have dir be the child's working directory. Interpret
\r
9929 * dir relative to the directory WinBoard loaded from. */
\r
9930 GetCurrentDirectory(MSG_SIZ, buf);
\r
9931 SetCurrentDirectory(installDir);
\r
9932 SetCurrentDirectory(dir);
\r
9934 /* Now create the child process. */
\r
9936 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9937 siStartInfo.lpReserved = NULL;
\r
9938 siStartInfo.lpDesktop = NULL;
\r
9939 siStartInfo.lpTitle = NULL;
\r
9940 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9941 siStartInfo.cbReserved2 = 0;
\r
9942 siStartInfo.lpReserved2 = NULL;
\r
9943 siStartInfo.hStdInput = hChildStdinRd;
\r
9944 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9945 siStartInfo.hStdError = hChildStdoutWr;
\r
9947 fSuccess = CreateProcess(NULL,
\r
9948 cmdLine, /* command line */
\r
9949 NULL, /* process security attributes */
\r
9950 NULL, /* primary thread security attrs */
\r
9951 TRUE, /* handles are inherited */
\r
9952 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9953 NULL, /* use parent's environment */
\r
9955 &siStartInfo, /* STARTUPINFO pointer */
\r
9956 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9958 err = GetLastError();
\r
9959 SetCurrentDirectory(buf); /* return to prev directory */
\r
9964 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9965 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9966 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9969 /* Close the handles we don't need in the parent */
\r
9970 CloseHandle(piProcInfo.hThread);
\r
9971 CloseHandle(hChildStdinRd);
\r
9972 CloseHandle(hChildStdoutWr);
\r
9974 /* Prepare return value */
\r
9975 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9976 cp->kind = CPReal;
\r
9977 cp->hProcess = piProcInfo.hProcess;
\r
9978 cp->pid = piProcInfo.dwProcessId;
\r
9979 cp->hFrom = hChildStdoutRdDup;
\r
9980 cp->hTo = hChildStdinWrDup;
\r
9982 *pr = (void *) cp;
\r
9984 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9985 2000 where engines sometimes don't see the initial command(s)
\r
9986 from WinBoard and hang. I don't understand how that can happen,
\r
9987 but the Sleep is harmless, so I've put it in. Others have also
\r
9988 reported what may be the same problem, so hopefully this will fix
\r
9989 it for them too. */
\r
9997 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9999 ChildProc *cp; int result;
\r
10001 cp = (ChildProc *) pr;
\r
10002 if (cp == NULL) return;
\r
10004 switch (cp->kind) {
\r
10006 /* TerminateProcess is considered harmful, so... */
\r
10007 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10008 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10009 /* The following doesn't work because the chess program
\r
10010 doesn't "have the same console" as WinBoard. Maybe
\r
10011 we could arrange for this even though neither WinBoard
\r
10012 nor the chess program uses a console for stdio? */
\r
10013 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10015 /* [AS] Special termination modes for misbehaving programs... */
\r
10016 if( signal == 9 ) {
\r
10017 result = TerminateProcess( cp->hProcess, 0 );
\r
10019 if ( appData.debugMode) {
\r
10020 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10023 else if( signal == 10 ) {
\r
10024 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10026 if( dw != WAIT_OBJECT_0 ) {
\r
10027 result = TerminateProcess( cp->hProcess, 0 );
\r
10029 if ( appData.debugMode) {
\r
10030 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10036 CloseHandle(cp->hProcess);
\r
10040 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10044 closesocket(cp->sock);
\r
10049 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10050 closesocket(cp->sock);
\r
10051 closesocket(cp->sock2);
\r
10059 InterruptChildProcess(ProcRef pr)
\r
10063 cp = (ChildProc *) pr;
\r
10064 if (cp == NULL) return;
\r
10065 switch (cp->kind) {
\r
10067 /* The following doesn't work because the chess program
\r
10068 doesn't "have the same console" as WinBoard. Maybe
\r
10069 we could arrange for this even though neither WinBoard
\r
10070 nor the chess program uses a console for stdio */
\r
10071 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10076 /* Can't interrupt */
\r
10080 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10087 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10089 char cmdLine[MSG_SIZ];
\r
10091 if (port[0] == NULLCHAR) {
\r
10092 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10094 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10096 return StartChildProcess(cmdLine, "", pr);
\r
10100 /* Code to open TCP sockets */
\r
10103 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10108 struct sockaddr_in sa, mysa;
\r
10109 struct hostent FAR *hp;
\r
10110 unsigned short uport;
\r
10111 WORD wVersionRequested;
\r
10114 /* Initialize socket DLL */
\r
10115 wVersionRequested = MAKEWORD(1, 1);
\r
10116 err = WSAStartup(wVersionRequested, &wsaData);
\r
10117 if (err != 0) return err;
\r
10119 /* Make socket */
\r
10120 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10121 err = WSAGetLastError();
\r
10126 /* Bind local address using (mostly) don't-care values.
\r
10128 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10129 mysa.sin_family = AF_INET;
\r
10130 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10131 uport = (unsigned short) 0;
\r
10132 mysa.sin_port = htons(uport);
\r
10133 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10134 == SOCKET_ERROR) {
\r
10135 err = WSAGetLastError();
\r
10140 /* Resolve remote host name */
\r
10141 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10142 if (!(hp = gethostbyname(host))) {
\r
10143 unsigned int b0, b1, b2, b3;
\r
10145 err = WSAGetLastError();
\r
10147 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10148 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10149 hp->h_addrtype = AF_INET;
\r
10150 hp->h_length = 4;
\r
10151 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10152 hp->h_addr_list[0] = (char *) malloc(4);
\r
10153 hp->h_addr_list[0][0] = (char) b0;
\r
10154 hp->h_addr_list[0][1] = (char) b1;
\r
10155 hp->h_addr_list[0][2] = (char) b2;
\r
10156 hp->h_addr_list[0][3] = (char) b3;
\r
10162 sa.sin_family = hp->h_addrtype;
\r
10163 uport = (unsigned short) atoi(port);
\r
10164 sa.sin_port = htons(uport);
\r
10165 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10167 /* Make connection */
\r
10168 if (connect(s, (struct sockaddr *) &sa,
\r
10169 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10170 err = WSAGetLastError();
\r
10175 /* Prepare return value */
\r
10176 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10177 cp->kind = CPSock;
\r
10179 *pr = (ProcRef *) cp;
\r
10185 OpenCommPort(char *name, ProcRef *pr)
\r
10190 char fullname[MSG_SIZ];
\r
10192 if (*name != '\\')
\r
10193 sprintf(fullname, "\\\\.\\%s", name);
\r
10195 strcpy(fullname, name);
\r
10197 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10198 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10199 if (h == (HANDLE) -1) {
\r
10200 return GetLastError();
\r
10204 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10206 /* Accumulate characters until a 100ms pause, then parse */
\r
10207 ct.ReadIntervalTimeout = 100;
\r
10208 ct.ReadTotalTimeoutMultiplier = 0;
\r
10209 ct.ReadTotalTimeoutConstant = 0;
\r
10210 ct.WriteTotalTimeoutMultiplier = 0;
\r
10211 ct.WriteTotalTimeoutConstant = 0;
\r
10212 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10214 /* Prepare return value */
\r
10215 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10216 cp->kind = CPComm;
\r
10219 *pr = (ProcRef *) cp;
\r
10225 OpenLoopback(ProcRef *pr)
\r
10227 DisplayFatalError("Not implemented", 0, 1);
\r
10233 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10237 SOCKET s, s2, s3;
\r
10238 struct sockaddr_in sa, mysa;
\r
10239 struct hostent FAR *hp;
\r
10240 unsigned short uport;
\r
10241 WORD wVersionRequested;
\r
10244 char stderrPortStr[MSG_SIZ];
\r
10246 /* Initialize socket DLL */
\r
10247 wVersionRequested = MAKEWORD(1, 1);
\r
10248 err = WSAStartup(wVersionRequested, &wsaData);
\r
10249 if (err != 0) return err;
\r
10251 /* Resolve remote host name */
\r
10252 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10253 if (!(hp = gethostbyname(host))) {
\r
10254 unsigned int b0, b1, b2, b3;
\r
10256 err = WSAGetLastError();
\r
10258 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10259 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10260 hp->h_addrtype = AF_INET;
\r
10261 hp->h_length = 4;
\r
10262 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10263 hp->h_addr_list[0] = (char *) malloc(4);
\r
10264 hp->h_addr_list[0][0] = (char) b0;
\r
10265 hp->h_addr_list[0][1] = (char) b1;
\r
10266 hp->h_addr_list[0][2] = (char) b2;
\r
10267 hp->h_addr_list[0][3] = (char) b3;
\r
10273 sa.sin_family = hp->h_addrtype;
\r
10274 uport = (unsigned short) 514;
\r
10275 sa.sin_port = htons(uport);
\r
10276 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10278 /* Bind local socket to unused "privileged" port address
\r
10280 s = INVALID_SOCKET;
\r
10281 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10282 mysa.sin_family = AF_INET;
\r
10283 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10284 for (fromPort = 1023;; fromPort--) {
\r
10285 if (fromPort < 0) {
\r
10287 return WSAEADDRINUSE;
\r
10289 if (s == INVALID_SOCKET) {
\r
10290 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10291 err = WSAGetLastError();
\r
10296 uport = (unsigned short) fromPort;
\r
10297 mysa.sin_port = htons(uport);
\r
10298 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10299 == SOCKET_ERROR) {
\r
10300 err = WSAGetLastError();
\r
10301 if (err == WSAEADDRINUSE) continue;
\r
10305 if (connect(s, (struct sockaddr *) &sa,
\r
10306 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10307 err = WSAGetLastError();
\r
10308 if (err == WSAEADDRINUSE) {
\r
10319 /* Bind stderr local socket to unused "privileged" port address
\r
10321 s2 = INVALID_SOCKET;
\r
10322 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10323 mysa.sin_family = AF_INET;
\r
10324 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10325 for (fromPort = 1023;; fromPort--) {
\r
10326 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10327 if (fromPort < 0) {
\r
10328 (void) closesocket(s);
\r
10330 return WSAEADDRINUSE;
\r
10332 if (s2 == INVALID_SOCKET) {
\r
10333 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10334 err = WSAGetLastError();
\r
10340 uport = (unsigned short) fromPort;
\r
10341 mysa.sin_port = htons(uport);
\r
10342 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10343 == SOCKET_ERROR) {
\r
10344 err = WSAGetLastError();
\r
10345 if (err == WSAEADDRINUSE) continue;
\r
10346 (void) closesocket(s);
\r
10350 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10351 err = WSAGetLastError();
\r
10352 if (err == WSAEADDRINUSE) {
\r
10354 s2 = INVALID_SOCKET;
\r
10357 (void) closesocket(s);
\r
10358 (void) closesocket(s2);
\r
10364 prevStderrPort = fromPort; // remember port used
\r
10365 sprintf(stderrPortStr, "%d", fromPort);
\r
10367 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10368 err = WSAGetLastError();
\r
10369 (void) closesocket(s);
\r
10370 (void) closesocket(s2);
\r
10375 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10376 err = WSAGetLastError();
\r
10377 (void) closesocket(s);
\r
10378 (void) closesocket(s2);
\r
10382 if (*user == NULLCHAR) user = UserName();
\r
10383 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10384 err = WSAGetLastError();
\r
10385 (void) closesocket(s);
\r
10386 (void) closesocket(s2);
\r
10390 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10391 err = WSAGetLastError();
\r
10392 (void) closesocket(s);
\r
10393 (void) closesocket(s2);
\r
10398 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10399 err = WSAGetLastError();
\r
10400 (void) closesocket(s);
\r
10401 (void) closesocket(s2);
\r
10405 (void) closesocket(s2); /* Stop listening */
\r
10407 /* Prepare return value */
\r
10408 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10409 cp->kind = CPRcmd;
\r
10412 *pr = (ProcRef *) cp;
\r
10419 AddInputSource(ProcRef pr, int lineByLine,
\r
10420 InputCallback func, VOIDSTAR closure)
\r
10422 InputSource *is, *is2 = NULL;
\r
10423 ChildProc *cp = (ChildProc *) pr;
\r
10425 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10426 is->lineByLine = lineByLine;
\r
10428 is->closure = closure;
\r
10429 is->second = NULL;
\r
10430 is->next = is->buf;
\r
10431 if (pr == NoProc) {
\r
10432 is->kind = CPReal;
\r
10433 consoleInputSource = is;
\r
10435 is->kind = cp->kind;
\r
10437 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10438 we create all threads suspended so that the is->hThread variable can be
\r
10439 safely assigned, then let the threads start with ResumeThread.
\r
10441 switch (cp->kind) {
\r
10443 is->hFile = cp->hFrom;
\r
10444 cp->hFrom = NULL; /* now owned by InputThread */
\r
10446 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10447 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10451 is->hFile = cp->hFrom;
\r
10452 cp->hFrom = NULL; /* now owned by InputThread */
\r
10454 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10455 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10459 is->sock = cp->sock;
\r
10461 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10462 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10466 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10468 is->sock = cp->sock;
\r
10469 is->second = is2;
\r
10470 is2->sock = cp->sock2;
\r
10471 is2->second = is2;
\r
10473 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10474 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10476 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10477 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10481 if( is->hThread != NULL ) {
\r
10482 ResumeThread( is->hThread );
\r
10485 if( is2 != NULL && is2->hThread != NULL ) {
\r
10486 ResumeThread( is2->hThread );
\r
10490 return (InputSourceRef) is;
\r
10494 RemoveInputSource(InputSourceRef isr)
\r
10498 is = (InputSource *) isr;
\r
10499 is->hThread = NULL; /* tell thread to stop */
\r
10500 CloseHandle(is->hThread);
\r
10501 if (is->second != NULL) {
\r
10502 is->second->hThread = NULL;
\r
10503 CloseHandle(is->second->hThread);
\r
10509 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10512 int outCount = SOCKET_ERROR;
\r
10513 ChildProc *cp = (ChildProc *) pr;
\r
10514 static OVERLAPPED ovl;
\r
10516 if (pr == NoProc) {
\r
10517 ConsoleOutput(message, count, FALSE);
\r
10521 if (ovl.hEvent == NULL) {
\r
10522 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10524 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10526 switch (cp->kind) {
\r
10529 outCount = send(cp->sock, message, count, 0);
\r
10530 if (outCount == SOCKET_ERROR) {
\r
10531 *outError = WSAGetLastError();
\r
10533 *outError = NO_ERROR;
\r
10538 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10539 &dOutCount, NULL)) {
\r
10540 *outError = NO_ERROR;
\r
10541 outCount = (int) dOutCount;
\r
10543 *outError = GetLastError();
\r
10548 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10549 &dOutCount, &ovl);
\r
10550 if (*outError == NO_ERROR) {
\r
10551 outCount = (int) dOutCount;
\r
10559 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10562 /* Ignore delay, not implemented for WinBoard */
\r
10563 return OutputToProcess(pr, message, count, outError);
\r
10568 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10569 char *buf, int count, int error)
\r
10571 DisplayFatalError("Not implemented", 0, 1);
\r
10574 /* see wgamelist.c for Game List functions */
\r
10575 /* see wedittags.c for Edit Tags functions */
\r
10582 char buf[MSG_SIZ];
\r
10585 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10586 f = fopen(buf, "r");
\r
10588 ProcessICSInitScript(f);
\r
10596 StartAnalysisClock()
\r
10598 if (analysisTimerEvent) return;
\r
10599 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10600 (UINT) 2000, NULL);
\r
10604 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10606 static HANDLE hwndText;
\r
10608 static int sizeX, sizeY;
\r
10609 int newSizeX, newSizeY, flags;
\r
10612 switch (message) {
\r
10613 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10614 /* Initialize the dialog items */
\r
10615 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10616 SetWindowText(hDlg, analysisTitle);
\r
10617 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10618 /* Size and position the dialog */
\r
10619 if (!analysisDialog) {
\r
10620 analysisDialog = hDlg;
\r
10621 flags = SWP_NOZORDER;
\r
10622 GetClientRect(hDlg, &rect);
\r
10623 sizeX = rect.right;
\r
10624 sizeY = rect.bottom;
\r
10625 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10626 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10627 WINDOWPLACEMENT wp;
\r
10628 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10629 wp.length = sizeof(WINDOWPLACEMENT);
\r
10631 wp.showCmd = SW_SHOW;
\r
10632 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10633 wp.rcNormalPosition.left = analysisX;
\r
10634 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10635 wp.rcNormalPosition.top = analysisY;
\r
10636 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10637 SetWindowPlacement(hDlg, &wp);
\r
10639 GetClientRect(hDlg, &rect);
\r
10640 newSizeX = rect.right;
\r
10641 newSizeY = rect.bottom;
\r
10642 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10643 newSizeX, newSizeY);
\r
10644 sizeX = newSizeX;
\r
10645 sizeY = newSizeY;
\r
10650 case WM_COMMAND: /* message: received a command */
\r
10651 switch (LOWORD(wParam)) {
\r
10653 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10654 ExitAnalyzeMode();
\r
10666 newSizeX = LOWORD(lParam);
\r
10667 newSizeY = HIWORD(lParam);
\r
10668 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10669 sizeX = newSizeX;
\r
10670 sizeY = newSizeY;
\r
10673 case WM_GETMINMAXINFO:
\r
10674 /* Prevent resizing window too small */
\r
10675 mmi = (MINMAXINFO *) lParam;
\r
10676 mmi->ptMinTrackSize.x = 100;
\r
10677 mmi->ptMinTrackSize.y = 100;
\r
10684 AnalysisPopUp(char* title, char* str)
\r
10690 EngineOutputPopUp();
\r
10693 if (str == NULL) str = "";
\r
10694 p = (char *) malloc(2 * strlen(str) + 2);
\r
10697 if (*str == '\n') *q++ = '\r';
\r
10701 if (analysisText != NULL) free(analysisText);
\r
10702 analysisText = p;
\r
10704 if (analysisDialog) {
\r
10705 SetWindowText(analysisDialog, title);
\r
10706 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10707 ShowWindow(analysisDialog, SW_SHOW);
\r
10709 analysisTitle = title;
\r
10710 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10711 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10712 hwndMain, (DLGPROC)lpProc);
\r
10713 FreeProcInstance(lpProc);
\r
10715 analysisDialogUp = TRUE;
\r
10719 AnalysisPopDown()
\r
10721 if (analysisDialog) {
\r
10722 ShowWindow(analysisDialog, SW_HIDE);
\r
10724 analysisDialogUp = FALSE;
\r
10729 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10731 highlightInfo.sq[0].x = fromX;
\r
10732 highlightInfo.sq[0].y = fromY;
\r
10733 highlightInfo.sq[1].x = toX;
\r
10734 highlightInfo.sq[1].y = toY;
\r
10738 ClearHighlights()
\r
10740 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10741 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10745 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10747 premoveHighlightInfo.sq[0].x = fromX;
\r
10748 premoveHighlightInfo.sq[0].y = fromY;
\r
10749 premoveHighlightInfo.sq[1].x = toX;
\r
10750 premoveHighlightInfo.sq[1].y = toY;
\r
10754 ClearPremoveHighlights()
\r
10756 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10757 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10761 ShutDownFrontEnd()
\r
10763 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10764 DeleteClipboardTempFiles();
\r
10770 if (IsIconic(hwndMain))
\r
10771 ShowWindow(hwndMain, SW_RESTORE);
\r
10773 SetActiveWindow(hwndMain);
\r
10777 * Prototypes for animation support routines
\r
10779 static void ScreenSquare(int column, int row, POINT * pt);
\r
10780 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10781 POINT frames[], int * nFrames);
\r
10785 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10786 { // [HGM] atomic: animate blast wave
\r
10788 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10789 explodeInfo.fromX = fromX;
\r
10790 explodeInfo.fromY = fromY;
\r
10791 explodeInfo.toX = toX;
\r
10792 explodeInfo.toY = toY;
\r
10793 for(i=1; i<nFrames; i++) {
\r
10794 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10795 DrawPosition(FALSE, NULL);
\r
10796 Sleep(appData.animSpeed);
\r
10798 explodeInfo.radius = 0;
\r
10799 DrawPosition(TRUE, NULL);
\r
10802 #define kFactor 4
\r
10805 AnimateMove(board, fromX, fromY, toX, toY)
\r
10812 ChessSquare piece;
\r
10813 POINT start, finish, mid;
\r
10814 POINT frames[kFactor * 2 + 1];
\r
10817 if (!appData.animate) return;
\r
10818 if (doingSizing) return;
\r
10819 if (fromY < 0 || fromX < 0) return;
\r
10820 piece = board[fromY][fromX];
\r
10821 if (piece >= EmptySquare) return;
\r
10823 ScreenSquare(fromX, fromY, &start);
\r
10824 ScreenSquare(toX, toY, &finish);
\r
10826 /* All pieces except knights move in straight line */
\r
10827 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10828 mid.x = start.x + (finish.x - start.x) / 2;
\r
10829 mid.y = start.y + (finish.y - start.y) / 2;
\r
10831 /* Knight: make diagonal movement then straight */
\r
10832 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10833 mid.x = start.x + (finish.x - start.x) / 2;
\r
10834 mid.y = finish.y;
\r
10836 mid.x = finish.x;
\r
10837 mid.y = start.y + (finish.y - start.y) / 2;
\r
10841 /* Don't use as many frames for very short moves */
\r
10842 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10843 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10845 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10847 animInfo.from.x = fromX;
\r
10848 animInfo.from.y = fromY;
\r
10849 animInfo.to.x = toX;
\r
10850 animInfo.to.y = toY;
\r
10851 animInfo.lastpos = start;
\r
10852 animInfo.piece = piece;
\r
10853 for (n = 0; n < nFrames; n++) {
\r
10854 animInfo.pos = frames[n];
\r
10855 DrawPosition(FALSE, NULL);
\r
10856 animInfo.lastpos = animInfo.pos;
\r
10857 Sleep(appData.animSpeed);
\r
10859 animInfo.pos = finish;
\r
10860 DrawPosition(FALSE, NULL);
\r
10861 animInfo.piece = EmptySquare;
\r
10862 if(gameInfo.variant == VariantAtomic &&
\r
10863 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10864 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10867 /* Convert board position to corner of screen rect and color */
\r
10870 ScreenSquare(column, row, pt)
\r
10871 int column; int row; POINT * pt;
\r
10874 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10875 pt->y = lineGap + row * (squareSize + lineGap);
\r
10877 pt->x = lineGap + column * (squareSize + lineGap);
\r
10878 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10882 /* Generate a series of frame coords from start->mid->finish.
\r
10883 The movement rate doubles until the half way point is
\r
10884 reached, then halves back down to the final destination,
\r
10885 which gives a nice slow in/out effect. The algorithmn
\r
10886 may seem to generate too many intermediates for short
\r
10887 moves, but remember that the purpose is to attract the
\r
10888 viewers attention to the piece about to be moved and
\r
10889 then to where it ends up. Too few frames would be less
\r
10893 Tween(start, mid, finish, factor, frames, nFrames)
\r
10894 POINT * start; POINT * mid;
\r
10895 POINT * finish; int factor;
\r
10896 POINT frames[]; int * nFrames;
\r
10898 int n, fraction = 1, count = 0;
\r
10900 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10901 for (n = 0; n < factor; n++)
\r
10903 for (n = 0; n < factor; n++) {
\r
10904 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10905 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10907 fraction = fraction / 2;
\r
10911 frames[count] = *mid;
\r
10914 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10916 for (n = 0; n < factor; n++) {
\r
10917 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10918 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10920 fraction = fraction * 2;
\r
10922 *nFrames = count;
\r
10926 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10928 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10930 EvalGraphSet( first, last, current, pvInfoList );
\r
10933 void SetProgramStats( FrontEndProgramStats * stats )
\r
10935 EngineOutputUpdate( stats );
\r