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 int commentUp = 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 int engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1395 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },
\r
1396 { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },
\r
1397 { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */
\r
1399 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1400 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1401 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1402 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1403 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1404 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1405 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1406 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1407 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1408 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1409 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1410 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1411 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1412 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1413 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1414 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1415 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1416 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1417 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1418 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1419 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1420 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1421 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1422 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1423 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1424 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1425 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1426 /* [AS] Layout stuff */
\r
1427 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1428 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1429 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1430 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1431 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1433 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1434 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1435 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1436 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1437 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1439 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1440 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1441 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1442 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1443 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1445 { NULL, ArgNone, NULL, FALSE }
\r
1449 /* Kludge for indirection files on command line */
\r
1450 char* lastIndirectionFilename;
\r
1451 ArgDescriptor argDescriptorIndirection =
\r
1452 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1456 ExitArgError(char *msg, char *badArg)
\r
1458 char buf[MSG_SIZ];
\r
1460 sprintf(buf, "%s %s", msg, badArg);
\r
1461 DisplayFatalError(buf, 0, 2);
\r
1466 ValidateInt(char *s)
\r
1469 if(*p == '-' || *p == '+') p++;
\r
1470 while(*p) if(!isdigit(*p++)) ExitArgError("Bad integer value", s);
\r
1474 /* Command line font name parser. NULL name means do nothing.
\r
1475 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1476 For backward compatibility, syntax without the colon is also
\r
1477 accepted, but font names with digits in them won't work in that case.
\r
1480 ParseFontName(char *name, MyFontParams *mfp)
\r
1483 if (name == NULL) return;
\r
1485 q = strchr(p, ':');
\r
1487 if (q - p >= sizeof(mfp->faceName))
\r
1488 ExitArgError("Font name too long:", name);
\r
1489 memcpy(mfp->faceName, p, q - p);
\r
1490 mfp->faceName[q - p] = NULLCHAR;
\r
1493 q = mfp->faceName;
\r
1494 while (*p && !isdigit(*p)) {
\r
1496 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1497 ExitArgError("Font name too long:", name);
\r
1499 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1502 if (!*p) ExitArgError("Font point size missing:", name);
\r
1503 mfp->pointSize = (float) atof(p);
\r
1504 mfp->bold = (strchr(p, 'b') != NULL);
\r
1505 mfp->italic = (strchr(p, 'i') != NULL);
\r
1506 mfp->underline = (strchr(p, 'u') != NULL);
\r
1507 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1508 mfp->charset = DEFAULT_CHARSET;
\r
1509 q = strchr(p, 'c');
\r
1511 mfp->charset = (BYTE) atoi(q+1);
\r
1514 /* Color name parser.
\r
1515 X version accepts X color names, but this one
\r
1516 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1518 ParseColorName(char *name)
\r
1520 int red, green, blue, count;
\r
1521 char buf[MSG_SIZ];
\r
1523 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1525 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1526 &red, &green, &blue);
\r
1529 sprintf(buf, "Can't parse color name %s", name);
\r
1530 DisplayError(buf, 0);
\r
1531 return RGB(0, 0, 0);
\r
1533 return PALETTERGB(red, green, blue);
\r
1537 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1539 char *e = argValue;
\r
1543 if (*e == 'b') eff |= CFE_BOLD;
\r
1544 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1545 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1546 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1547 else if (*e == '#' || isdigit(*e)) break;
\r
1551 *color = ParseColorName(e);
\r
1556 ParseBoardSize(char *name)
\r
1558 BoardSize bs = SizeTiny;
\r
1559 while (sizeInfo[bs].name != NULL) {
\r
1560 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1563 ExitArgError("Unrecognized board size value", name);
\r
1564 return bs; /* not reached */
\r
1569 StringGet(void *getClosure)
\r
1571 char **p = (char **) getClosure;
\r
1576 FileGet(void *getClosure)
\r
1579 FILE* f = (FILE*) getClosure;
\r
1582 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1589 /* Parse settings file named "name". If file found, return the
\r
1590 full name in fullname and return TRUE; else return FALSE */
\r
1592 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1596 int ok; char buf[MSG_SIZ];
\r
1598 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1599 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1600 sprintf(buf, "%s.ini", name);
\r
1601 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1604 f = fopen(fullname, "r");
\r
1606 ParseArgs(FileGet, f);
\r
1615 ParseArgs(GetFunc get, void *cl)
\r
1617 char argName[ARG_MAX];
\r
1618 char argValue[ARG_MAX];
\r
1619 ArgDescriptor *ad;
\r
1628 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1629 if (ch == NULLCHAR) break;
\r
1631 /* Comment to end of line */
\r
1633 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1635 } else if (ch == '/' || ch == '-') {
\r
1638 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1639 ch != '\n' && ch != '\t') {
\r
1645 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1646 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1648 if (ad->argName == NULL)
\r
1649 ExitArgError("Unrecognized argument", argName);
\r
1651 } else if (ch == '@') {
\r
1652 /* Indirection file */
\r
1653 ad = &argDescriptorIndirection;
\r
1656 /* Positional argument */
\r
1657 ad = &argDescriptors[posarg++];
\r
1658 strcpy(argName, ad->argName);
\r
1661 if (ad->argType == ArgTrue) {
\r
1662 *(Boolean *) ad->argLoc = TRUE;
\r
1665 if (ad->argType == ArgFalse) {
\r
1666 *(Boolean *) ad->argLoc = FALSE;
\r
1670 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1671 if (ch == NULLCHAR || ch == '\n') {
\r
1672 ExitArgError("No value provided for argument", argName);
\r
1676 // Quoting with { }. No characters have to (or can) be escaped.
\r
1677 // Thus the string cannot contain a '}' character.
\r
1697 } else if (ch == '\'' || ch == '"') {
\r
1698 // Quoting with ' ' or " ", with \ as escape character.
\r
1699 // Inconvenient for long strings that may contain Windows filenames.
\r
1716 if (ch == start) {
\r
1725 if (ad->argType == ArgFilename
\r
1726 || ad->argType == ArgSettingsFilename) {
\r
1732 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1756 for (i = 0; i < 3; i++) {
\r
1757 if (ch >= '0' && ch <= '7') {
\r
1758 octval = octval*8 + (ch - '0');
\r
1765 *q++ = (char) octval;
\r
1776 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1783 switch (ad->argType) {
\r
1785 *(int *) ad->argLoc = ValidateInt(argValue);
\r
1789 *(int *) ad->argLoc = ValidateInt(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1793 *(int *) ad->argLoc = ValidateInt(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1797 *(int *) ad->argLoc = ValidateInt(argValue);
\r
1798 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1802 *(float *) ad->argLoc = (float) atof(argValue);
\r
1807 *(char **) ad->argLoc = strdup(argValue);
\r
1810 case ArgSettingsFilename:
\r
1812 char fullname[MSG_SIZ];
\r
1813 if (ParseSettingsFile(argValue, fullname)) {
\r
1814 if (ad->argLoc != NULL) {
\r
1815 *(char **) ad->argLoc = strdup(fullname);
\r
1818 if (ad->argLoc != NULL) {
\r
1820 ExitArgError("Failed to open indirection file", argValue);
\r
1827 switch (argValue[0]) {
\r
1830 *(Boolean *) ad->argLoc = TRUE;
\r
1834 *(Boolean *) ad->argLoc = FALSE;
\r
1837 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1843 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1846 case ArgAttribs: {
\r
1847 ColorClass cc = (ColorClass)ad->argLoc;
\r
1848 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1852 case ArgBoardSize:
\r
1853 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1857 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1860 case ArgCommSettings:
\r
1861 ParseCommSettings(argValue, &dcb);
\r
1865 ExitArgError("Unrecognized argument", argValue);
\r
1874 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1876 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1877 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1880 lf->lfEscapement = 0;
\r
1881 lf->lfOrientation = 0;
\r
1882 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1883 lf->lfItalic = mfp->italic;
\r
1884 lf->lfUnderline = mfp->underline;
\r
1885 lf->lfStrikeOut = mfp->strikeout;
\r
1886 lf->lfCharSet = mfp->charset;
\r
1887 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1888 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1889 lf->lfQuality = DEFAULT_QUALITY;
\r
1890 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1891 strcpy(lf->lfFaceName, mfp->faceName);
\r
1895 CreateFontInMF(MyFont *mf)
\r
1897 LFfromMFP(&mf->lf, &mf->mfp);
\r
1898 if (mf->hf) DeleteObject(mf->hf);
\r
1899 mf->hf = CreateFontIndirect(&mf->lf);
\r
1903 SetDefaultTextAttribs()
\r
1906 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1907 ParseAttribs(&textAttribs[cc].color,
\r
1908 &textAttribs[cc].effects,
\r
1909 defaultTextAttribs[cc]);
\r
1914 SetDefaultSounds()
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 textAttribs[cc].sound.name = strdup("");
\r
1920 textAttribs[cc].sound.data = NULL;
\r
1922 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1923 sounds[sc].name = strdup("");
\r
1924 sounds[sc].data = NULL;
\r
1926 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1934 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1935 MyLoadSound(&textAttribs[cc].sound);
\r
1937 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1938 MyLoadSound(&sounds[sc]);
\r
1943 InitAppData(LPSTR lpCmdLine)
\r
1946 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1949 programName = szAppName;
\r
1951 /* Initialize to defaults */
\r
1952 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1953 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1954 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1955 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1956 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1957 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1958 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1959 SetDefaultTextAttribs();
\r
1960 SetDefaultSounds();
\r
1961 appData.movesPerSession = MOVES_PER_SESSION;
\r
1962 appData.initString = INIT_STRING;
\r
1963 appData.secondInitString = INIT_STRING;
\r
1964 appData.firstComputerString = COMPUTER_STRING;
\r
1965 appData.secondComputerString = COMPUTER_STRING;
\r
1966 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1967 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1968 appData.firstPlaysBlack = FALSE;
\r
1969 appData.noChessProgram = FALSE;
\r
1970 chessProgram = FALSE;
\r
1971 appData.firstHost = FIRST_HOST;
\r
1972 appData.secondHost = SECOND_HOST;
\r
1973 appData.firstDirectory = FIRST_DIRECTORY;
\r
1974 appData.secondDirectory = SECOND_DIRECTORY;
\r
1975 appData.bitmapDirectory = "";
\r
1976 appData.remoteShell = REMOTE_SHELL;
\r
1977 appData.remoteUser = "";
\r
1978 appData.timeDelay = TIME_DELAY;
\r
1979 appData.timeControl = TIME_CONTROL;
\r
1980 appData.timeIncrement = TIME_INCREMENT;
\r
1981 appData.icsActive = FALSE;
\r
1982 appData.icsHost = "";
\r
1983 appData.icsPort = ICS_PORT;
\r
1984 appData.icsCommPort = ICS_COMM_PORT;
\r
1985 appData.icsLogon = ICS_LOGON;
\r
1986 appData.icsHelper = "";
\r
1987 appData.useTelnet = FALSE;
\r
1988 appData.telnetProgram = TELNET_PROGRAM;
\r
1989 appData.gateway = "";
\r
1990 appData.loadGameFile = "";
\r
1991 appData.loadGameIndex = 0;
\r
1992 appData.saveGameFile = "";
\r
1993 appData.autoSaveGames = FALSE;
\r
1994 appData.loadPositionFile = "";
\r
1995 appData.loadPositionIndex = 1;
\r
1996 appData.savePositionFile = "";
\r
1997 appData.matchMode = FALSE;
\r
1998 appData.matchGames = 0;
\r
1999 appData.monoMode = FALSE;
\r
2000 appData.debugMode = FALSE;
\r
2001 appData.clockMode = TRUE;
\r
2002 boardSize = (BoardSize) -1; /* determine by screen size */
\r
2003 appData.Iconic = FALSE; /*unused*/
\r
2004 appData.searchTime = "";
\r
2005 appData.searchDepth = 0;
\r
2006 appData.showCoords = FALSE;
\r
2007 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
2008 appData.autoCallFlag = FALSE;
\r
2009 appData.flipView = FALSE;
\r
2010 appData.autoFlipView = TRUE;
\r
2011 appData.cmailGameName = "";
\r
2012 appData.alwaysPromoteToQueen = FALSE;
\r
2013 appData.oldSaveStyle = FALSE;
\r
2014 appData.quietPlay = FALSE;
\r
2015 appData.showThinking = FALSE;
\r
2016 appData.ponderNextMove = TRUE;
\r
2017 appData.periodicUpdates = TRUE;
\r
2018 appData.popupExitMessage = TRUE;
\r
2019 appData.popupMoveErrors = FALSE;
\r
2020 appData.autoObserve = FALSE;
\r
2021 appData.autoComment = FALSE;
\r
2022 appData.animate = TRUE;
\r
2023 appData.animSpeed = 10;
\r
2024 appData.animateDragging = TRUE;
\r
2025 appData.highlightLastMove = TRUE;
\r
2026 appData.getMoveList = TRUE;
\r
2027 appData.testLegality = TRUE;
\r
2028 appData.premove = TRUE;
\r
2029 appData.premoveWhite = FALSE;
\r
2030 appData.premoveWhiteText = "";
\r
2031 appData.premoveBlack = FALSE;
\r
2032 appData.premoveBlackText = "";
\r
2033 appData.icsAlarm = TRUE;
\r
2034 appData.icsAlarmTime = 5000;
\r
2035 appData.autoRaiseBoard = TRUE;
\r
2036 appData.localLineEditing = TRUE;
\r
2037 appData.colorize = TRUE;
\r
2038 appData.reuseFirst = TRUE;
\r
2039 appData.reuseSecond = TRUE;
\r
2040 appData.blindfold = FALSE;
\r
2041 appData.icsEngineAnalyze = FALSE;
\r
2042 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2043 dcb.DCBlength = sizeof(DCB);
\r
2044 dcb.BaudRate = 9600;
\r
2045 dcb.fBinary = TRUE;
\r
2046 dcb.fParity = FALSE;
\r
2047 dcb.fOutxCtsFlow = FALSE;
\r
2048 dcb.fOutxDsrFlow = FALSE;
\r
2049 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2050 dcb.fDsrSensitivity = FALSE;
\r
2051 dcb.fTXContinueOnXoff = TRUE;
\r
2052 dcb.fOutX = FALSE;
\r
2054 dcb.fNull = FALSE;
\r
2055 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2056 dcb.fAbortOnError = FALSE;
\r
2058 dcb.Parity = SPACEPARITY;
\r
2059 dcb.StopBits = ONESTOPBIT;
\r
2060 settingsFileName = SETTINGS_FILE;
\r
2061 saveSettingsOnExit = TRUE;
\r
2062 boardX = CW_USEDEFAULT;
\r
2063 boardY = CW_USEDEFAULT;
\r
2064 analysisX = CW_USEDEFAULT;
\r
2065 analysisY = CW_USEDEFAULT;
\r
2066 analysisW = CW_USEDEFAULT;
\r
2067 analysisH = CW_USEDEFAULT;
\r
2068 commentX = CW_USEDEFAULT;
\r
2069 commentY = CW_USEDEFAULT;
\r
2070 commentW = CW_USEDEFAULT;
\r
2071 commentH = CW_USEDEFAULT;
\r
2072 editTagsX = CW_USEDEFAULT;
\r
2073 editTagsY = CW_USEDEFAULT;
\r
2074 editTagsW = CW_USEDEFAULT;
\r
2075 editTagsH = CW_USEDEFAULT;
\r
2076 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2077 icsNames = ICS_NAMES;
\r
2078 firstChessProgramNames = FCP_NAMES;
\r
2079 secondChessProgramNames = SCP_NAMES;
\r
2080 appData.initialMode = "";
\r
2081 appData.variant = "normal";
\r
2082 appData.firstProtocolVersion = PROTOVER;
\r
2083 appData.secondProtocolVersion = PROTOVER;
\r
2084 appData.showButtonBar = TRUE;
\r
2086 /* [AS] New properties (see comments in header file) */
\r
2087 appData.firstScoreIsAbsolute = FALSE;
\r
2088 appData.secondScoreIsAbsolute = FALSE;
\r
2089 appData.saveExtendedInfoInPGN = FALSE;
\r
2090 appData.hideThinkingFromHuman = FALSE;
\r
2091 appData.liteBackTextureFile = "";
\r
2092 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2093 appData.darkBackTextureFile = "";
\r
2094 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2095 appData.renderPiecesWithFont = "";
\r
2096 appData.fontToPieceTable = "";
\r
2097 appData.fontBackColorWhite = 0;
\r
2098 appData.fontForeColorWhite = 0;
\r
2099 appData.fontBackColorBlack = 0;
\r
2100 appData.fontForeColorBlack = 0;
\r
2101 appData.fontPieceSize = 80;
\r
2102 appData.overrideLineGap = 1;
\r
2103 appData.adjudicateLossThreshold = 0;
\r
2104 appData.delayBeforeQuit = 0;
\r
2105 appData.delayAfterQuit = 0;
\r
2106 appData.nameOfDebugFile = "winboard.debug";
\r
2107 appData.pgnEventHeader = "Computer Chess Game";
\r
2108 appData.defaultFrcPosition = -1;
\r
2109 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2110 appData.saveOutOfBookInfo = TRUE;
\r
2111 appData.showEvalInMoveHistory = TRUE;
\r
2112 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2113 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2114 appData.highlightMoveWithArrow = FALSE;
\r
2115 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2116 appData.useStickyWindows = TRUE;
\r
2117 appData.adjudicateDrawMoves = 0;
\r
2118 appData.autoDisplayComment = TRUE;
\r
2119 appData.autoDisplayTags = TRUE;
\r
2120 appData.firstIsUCI = FALSE;
\r
2121 appData.secondIsUCI = FALSE;
\r
2122 appData.firstHasOwnBookUCI = TRUE;
\r
2123 appData.secondHasOwnBookUCI = TRUE;
\r
2124 appData.polyglotDir = "";
\r
2125 appData.usePolyglotBook = FALSE;
\r
2126 appData.polyglotBook = "";
\r
2127 appData.defaultHashSize = 64;
\r
2128 appData.defaultCacheSizeEGTB = 4;
\r
2129 appData.defaultPathEGTB = "c:\\egtb";
\r
2130 appData.firstOptions = "";
\r
2131 appData.secondOptions = "";
\r
2133 InitWindowPlacement( &wpGameList );
\r
2134 InitWindowPlacement( &wpMoveHistory );
\r
2135 InitWindowPlacement( &wpEvalGraph );
\r
2136 InitWindowPlacement( &wpEngineOutput );
\r
2137 InitWindowPlacement( &wpConsole );
\r
2139 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2140 appData.NrFiles = -1;
\r
2141 appData.NrRanks = -1;
\r
2142 appData.holdingsSize = -1;
\r
2143 appData.testClaims = FALSE;
\r
2144 appData.checkMates = FALSE;
\r
2145 appData.materialDraws= FALSE;
\r
2146 appData.trivialDraws = FALSE;
\r
2147 appData.ruleMoves = 51;
\r
2148 appData.drawRepeats = 6;
\r
2149 appData.matchPause = 10000;
\r
2150 appData.alphaRank = FALSE;
\r
2151 appData.allWhite = FALSE;
\r
2152 appData.upsideDown = FALSE;
\r
2153 appData.serverPause = 15;
\r
2154 appData.serverMovesName = NULL;
\r
2155 appData.suppressLoadMoves = FALSE;
\r
2156 appData.firstTimeOdds = 1;
\r
2157 appData.secondTimeOdds = 1;
\r
2158 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2159 appData.secondAccumulateTC = 1;
\r
2160 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2161 appData.secondNPS = -1;
\r
2162 appData.engineComments = 1;
\r
2163 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2164 appData.egtFormats = "";
\r
2167 appData.zippyTalk = ZIPPY_TALK;
\r
2168 appData.zippyPlay = ZIPPY_PLAY;
\r
2169 appData.zippyLines = ZIPPY_LINES;
\r
2170 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2171 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2172 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2173 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2174 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2175 appData.zippyUseI = ZIPPY_USE_I;
\r
2176 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2177 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2178 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2179 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2180 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2181 appData.zippyAbort = ZIPPY_ABORT;
\r
2182 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2183 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2184 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2187 /* Point font array elements to structures and
\r
2188 parse default font names */
\r
2189 for (i=0; i<NUM_FONTS; i++) {
\r
2190 for (j=0; j<NUM_SIZES; j++) {
\r
2191 font[j][i] = &fontRec[j][i];
\r
2192 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2196 /* Parse default settings file if any */
\r
2197 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2198 settingsFileName = strdup(buf);
\r
2201 /* Parse command line */
\r
2202 ParseArgs(StringGet, &lpCmdLine);
\r
2204 /* [HGM] make sure board size is acceptable */
\r
2205 if(appData.NrFiles > BOARD_SIZE ||
\r
2206 appData.NrRanks > BOARD_SIZE )
\r
2207 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2209 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2210 * with options from the command line, we now make an even higher priority
\r
2211 * overrule by WB options attached to the engine command line. This so that
\r
2212 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2215 if(appData.firstChessProgram != NULL) {
\r
2216 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2217 static char *f = "first";
\r
2218 char buf[MSG_SIZ], *q = buf;
\r
2219 if(p != NULL) { // engine command line contains WinBoard options
\r
2220 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2221 ParseArgs(StringGet, &q);
\r
2222 p[-1] = 0; // cut them offengine command line
\r
2225 // now do same for second chess program
\r
2226 if(appData.secondChessProgram != NULL) {
\r
2227 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2228 static char *s = "second";
\r
2229 char buf[MSG_SIZ], *q = buf;
\r
2230 if(p != NULL) { // engine command line contains WinBoard options
\r
2231 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2232 ParseArgs(StringGet, &q);
\r
2233 p[-1] = 0; // cut them offengine command line
\r
2238 /* Propagate options that affect others */
\r
2239 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2240 if (appData.icsActive || appData.noChessProgram) {
\r
2241 chessProgram = FALSE; /* not local chess program mode */
\r
2244 /* Open startup dialog if needed */
\r
2245 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2246 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2247 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2248 *appData.secondChessProgram == NULLCHAR))) {
\r
2251 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2252 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2253 FreeProcInstance(lpProc);
\r
2256 /* Make sure save files land in the right (?) directory */
\r
2257 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2258 appData.saveGameFile = strdup(buf);
\r
2260 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2261 appData.savePositionFile = strdup(buf);
\r
2264 /* Finish initialization for fonts and sounds */
\r
2265 for (i=0; i<NUM_FONTS; i++) {
\r
2266 for (j=0; j<NUM_SIZES; j++) {
\r
2267 CreateFontInMF(font[j][i]);
\r
2270 /* xboard, and older WinBoards, controlled the move sound with the
\r
2271 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2272 always turn the option on (so that the backend will call us),
\r
2273 then let the user turn the sound off by setting it to silence if
\r
2274 desired. To accommodate old winboard.ini files saved by old
\r
2275 versions of WinBoard, we also turn off the sound if the option
\r
2276 was initially set to false. */
\r
2277 if (!appData.ringBellAfterMoves) {
\r
2278 sounds[(int)SoundMove].name = strdup("");
\r
2279 appData.ringBellAfterMoves = TRUE;
\r
2281 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2282 SetCurrentDirectory(installDir);
\r
2284 SetCurrentDirectory(currDir);
\r
2286 p = icsTextMenuString;
\r
2287 if (p[0] == '@') {
\r
2288 FILE* f = fopen(p + 1, "r");
\r
2290 DisplayFatalError(p + 1, errno, 2);
\r
2293 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2295 buf[i] = NULLCHAR;
\r
2298 ParseIcsTextMenu(strdup(p));
\r
2305 HMENU hmenu = GetMenu(hwndMain);
\r
2307 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2308 MF_BYCOMMAND|((appData.icsActive &&
\r
2309 *appData.icsCommPort != NULLCHAR) ?
\r
2310 MF_ENABLED : MF_GRAYED));
\r
2311 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2312 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2313 MF_CHECKED : MF_UNCHECKED));
\r
2318 SaveSettings(char* name)
\r
2321 ArgDescriptor *ad;
\r
2322 WINDOWPLACEMENT wp;
\r
2323 char dir[MSG_SIZ];
\r
2325 if (!hwndMain) return;
\r
2327 GetCurrentDirectory(MSG_SIZ, dir);
\r
2328 SetCurrentDirectory(installDir);
\r
2329 f = fopen(name, "w");
\r
2330 SetCurrentDirectory(dir);
\r
2332 DisplayError(name, errno);
\r
2335 fprintf(f, ";\n");
\r
2336 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2337 fprintf(f, ";\n");
\r
2338 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2339 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2340 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2341 fprintf(f, ";\n");
\r
2343 wp.length = sizeof(WINDOWPLACEMENT);
\r
2344 GetWindowPlacement(hwndMain, &wp);
\r
2345 boardX = wp.rcNormalPosition.left;
\r
2346 boardY = wp.rcNormalPosition.top;
\r
2348 if (hwndConsole) {
\r
2349 GetWindowPlacement(hwndConsole, &wp);
\r
2350 wpConsole.x = wp.rcNormalPosition.left;
\r
2351 wpConsole.y = wp.rcNormalPosition.top;
\r
2352 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (analysisDialog) {
\r
2357 GetWindowPlacement(analysisDialog, &wp);
\r
2358 analysisX = wp.rcNormalPosition.left;
\r
2359 analysisY = wp.rcNormalPosition.top;
\r
2360 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (commentDialog) {
\r
2365 GetWindowPlacement(commentDialog, &wp);
\r
2366 commentX = wp.rcNormalPosition.left;
\r
2367 commentY = wp.rcNormalPosition.top;
\r
2368 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 if (editTagsDialog) {
\r
2373 GetWindowPlacement(editTagsDialog, &wp);
\r
2374 editTagsX = wp.rcNormalPosition.left;
\r
2375 editTagsY = wp.rcNormalPosition.top;
\r
2376 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2377 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2380 if (gameListDialog) {
\r
2381 GetWindowPlacement(gameListDialog, &wp);
\r
2382 wpGameList.x = wp.rcNormalPosition.left;
\r
2383 wpGameList.y = wp.rcNormalPosition.top;
\r
2384 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2385 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2388 /* [AS] Move history */
\r
2389 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2391 if( moveHistoryDialog ) {
\r
2392 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2393 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2394 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2395 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2396 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2399 /* [AS] Eval graph */
\r
2400 wpEvalGraph.visible = EvalGraphIsUp();
\r
2402 if( evalGraphDialog ) {
\r
2403 GetWindowPlacement(evalGraphDialog, &wp);
\r
2404 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2405 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2406 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2407 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2410 /* [AS] Engine output */
\r
2411 wpEngineOutput.visible = EngineOutputIsUp();
\r
2413 if( engineOutputDialog ) {
\r
2414 GetWindowPlacement(engineOutputDialog, &wp);
\r
2415 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2416 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2417 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2418 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2421 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2422 if (!ad->save) continue;
\r
2423 switch (ad->argType) {
\r
2426 char *p = *(char **)ad->argLoc;
\r
2427 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2428 /* Quote multiline values or \-containing values
\r
2429 with { } if possible */
\r
2430 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2432 /* Else quote with " " */
\r
2433 fprintf(f, "/%s=\"", ad->argName);
\r
2435 if (*p == '\n') fprintf(f, "\n");
\r
2436 else if (*p == '\r') fprintf(f, "\\r");
\r
2437 else if (*p == '\t') fprintf(f, "\\t");
\r
2438 else if (*p == '\b') fprintf(f, "\\b");
\r
2439 else if (*p == '\f') fprintf(f, "\\f");
\r
2440 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2441 else if (*p == '\"') fprintf(f, "\\\"");
\r
2442 else if (*p == '\\') fprintf(f, "\\\\");
\r
2446 fprintf(f, "\"\n");
\r
2452 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2455 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2458 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2461 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2464 fprintf(f, "/%s=%s\n", ad->argName,
\r
2465 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2468 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2471 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2475 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2476 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2477 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2482 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2483 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2484 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2485 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2486 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2487 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2488 (ta->effects) ? " " : "",
\r
2489 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2493 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2494 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2496 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2499 case ArgBoardSize:
\r
2500 fprintf(f, "/%s=%s\n", ad->argName,
\r
2501 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2506 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2507 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2508 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2509 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2510 ad->argName, mfp->faceName, mfp->pointSize,
\r
2511 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2512 mfp->bold ? "b" : "",
\r
2513 mfp->italic ? "i" : "",
\r
2514 mfp->underline ? "u" : "",
\r
2515 mfp->strikeout ? "s" : "",
\r
2516 (int)mfp->charset);
\r
2520 case ArgCommSettings:
\r
2521 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2523 case ArgSettingsFilename: ;
\r
2531 /*---------------------------------------------------------------------------*\
\r
2533 * GDI board drawing routines
\r
2535 \*---------------------------------------------------------------------------*/
\r
2537 /* [AS] Draw square using background texture */
\r
2538 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2543 return; /* Should never happen! */
\r
2546 SetGraphicsMode( dst, GM_ADVANCED );
\r
2553 /* X reflection */
\r
2558 x.eDx = (FLOAT) dw + dx - 1;
\r
2561 SetWorldTransform( dst, &x );
\r
2564 /* Y reflection */
\r
2570 x.eDy = (FLOAT) dh + dy - 1;
\r
2572 SetWorldTransform( dst, &x );
\r
2580 x.eDx = (FLOAT) dx;
\r
2581 x.eDy = (FLOAT) dy;
\r
2584 SetWorldTransform( dst, &x );
\r
2588 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2596 SetWorldTransform( dst, &x );
\r
2598 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2601 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2603 PM_WP = (int) WhitePawn,
\r
2604 PM_WN = (int) WhiteKnight,
\r
2605 PM_WB = (int) WhiteBishop,
\r
2606 PM_WR = (int) WhiteRook,
\r
2607 PM_WQ = (int) WhiteQueen,
\r
2608 PM_WF = (int) WhiteFerz,
\r
2609 PM_WW = (int) WhiteWazir,
\r
2610 PM_WE = (int) WhiteAlfil,
\r
2611 PM_WM = (int) WhiteMan,
\r
2612 PM_WO = (int) WhiteCannon,
\r
2613 PM_WU = (int) WhiteUnicorn,
\r
2614 PM_WH = (int) WhiteNightrider,
\r
2615 PM_WA = (int) WhiteAngel,
\r
2616 PM_WC = (int) WhiteMarshall,
\r
2617 PM_WAB = (int) WhiteCardinal,
\r
2618 PM_WD = (int) WhiteDragon,
\r
2619 PM_WL = (int) WhiteLance,
\r
2620 PM_WS = (int) WhiteCobra,
\r
2621 PM_WV = (int) WhiteFalcon,
\r
2622 PM_WSG = (int) WhiteSilver,
\r
2623 PM_WG = (int) WhiteGrasshopper,
\r
2624 PM_WK = (int) WhiteKing,
\r
2625 PM_BP = (int) BlackPawn,
\r
2626 PM_BN = (int) BlackKnight,
\r
2627 PM_BB = (int) BlackBishop,
\r
2628 PM_BR = (int) BlackRook,
\r
2629 PM_BQ = (int) BlackQueen,
\r
2630 PM_BF = (int) BlackFerz,
\r
2631 PM_BW = (int) BlackWazir,
\r
2632 PM_BE = (int) BlackAlfil,
\r
2633 PM_BM = (int) BlackMan,
\r
2634 PM_BO = (int) BlackCannon,
\r
2635 PM_BU = (int) BlackUnicorn,
\r
2636 PM_BH = (int) BlackNightrider,
\r
2637 PM_BA = (int) BlackAngel,
\r
2638 PM_BC = (int) BlackMarshall,
\r
2639 PM_BG = (int) BlackGrasshopper,
\r
2640 PM_BAB = (int) BlackCardinal,
\r
2641 PM_BD = (int) BlackDragon,
\r
2642 PM_BL = (int) BlackLance,
\r
2643 PM_BS = (int) BlackCobra,
\r
2644 PM_BV = (int) BlackFalcon,
\r
2645 PM_BSG = (int) BlackSilver,
\r
2646 PM_BK = (int) BlackKing
\r
2649 static HFONT hPieceFont = NULL;
\r
2650 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2651 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2652 static int fontBitmapSquareSize = 0;
\r
2653 static char pieceToFontChar[(int) EmptySquare] =
\r
2654 { 'p', 'n', 'b', 'r', 'q',
\r
2655 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2656 'k', 'o', 'm', 'v', 't', 'w',
\r
2657 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2660 extern BOOL SetCharTable( char *table, const char * map );
\r
2661 /* [HGM] moved to backend.c */
\r
2663 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2666 BYTE r1 = GetRValue( color );
\r
2667 BYTE g1 = GetGValue( color );
\r
2668 BYTE b1 = GetBValue( color );
\r
2674 /* Create a uniform background first */
\r
2675 hbrush = CreateSolidBrush( color );
\r
2676 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2677 FillRect( hdc, &rc, hbrush );
\r
2678 DeleteObject( hbrush );
\r
2681 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2682 int steps = squareSize / 2;
\r
2685 for( i=0; i<steps; i++ ) {
\r
2686 BYTE r = r1 - (r1-r2) * i / steps;
\r
2687 BYTE g = g1 - (g1-g2) * i / steps;
\r
2688 BYTE b = b1 - (b1-b2) * i / steps;
\r
2690 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2691 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2692 FillRect( hdc, &rc, hbrush );
\r
2693 DeleteObject(hbrush);
\r
2696 else if( mode == 2 ) {
\r
2697 /* Diagonal gradient, good more or less for every piece */
\r
2698 POINT triangle[3];
\r
2699 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2700 HBRUSH hbrush_old;
\r
2701 int steps = squareSize;
\r
2704 triangle[0].x = squareSize - steps;
\r
2705 triangle[0].y = squareSize;
\r
2706 triangle[1].x = squareSize;
\r
2707 triangle[1].y = squareSize;
\r
2708 triangle[2].x = squareSize;
\r
2709 triangle[2].y = squareSize - steps;
\r
2711 for( i=0; i<steps; i++ ) {
\r
2712 BYTE r = r1 - (r1-r2) * i / steps;
\r
2713 BYTE g = g1 - (g1-g2) * i / steps;
\r
2714 BYTE b = b1 - (b1-b2) * i / steps;
\r
2716 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2717 hbrush_old = SelectObject( hdc, hbrush );
\r
2718 Polygon( hdc, triangle, 3 );
\r
2719 SelectObject( hdc, hbrush_old );
\r
2720 DeleteObject(hbrush);
\r
2725 SelectObject( hdc, hpen );
\r
2730 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2731 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2732 piece: follow the steps as explained below.
\r
2734 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2738 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2742 int backColor = whitePieceColor;
\r
2743 int foreColor = blackPieceColor;
\r
2745 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2746 backColor = appData.fontBackColorWhite;
\r
2747 foreColor = appData.fontForeColorWhite;
\r
2749 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2750 backColor = appData.fontBackColorBlack;
\r
2751 foreColor = appData.fontForeColorBlack;
\r
2755 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2757 hbm_old = SelectObject( hdc, hbm );
\r
2761 rc.right = squareSize;
\r
2762 rc.bottom = squareSize;
\r
2764 /* Step 1: background is now black */
\r
2765 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2767 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2769 pt.x = (squareSize - sz.cx) / 2;
\r
2770 pt.y = (squareSize - sz.cy) / 2;
\r
2772 SetBkMode( hdc, TRANSPARENT );
\r
2773 SetTextColor( hdc, chroma );
\r
2774 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2775 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2777 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2778 /* Step 3: the area outside the piece is filled with white */
\r
2779 // FloodFill( hdc, 0, 0, chroma );
\r
2780 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2781 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2782 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2783 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2784 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2786 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2787 but if the start point is not inside the piece we're lost!
\r
2788 There should be a better way to do this... if we could create a region or path
\r
2789 from the fill operation we would be fine for example.
\r
2791 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2792 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2794 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2795 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2796 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2798 SelectObject( dc2, bm2 );
\r
2799 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2800 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2801 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2802 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2803 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2806 DeleteObject( bm2 );
\r
2809 SetTextColor( hdc, 0 );
\r
2811 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2812 draw the piece again in black for safety.
\r
2814 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2816 SelectObject( hdc, hbm_old );
\r
2818 if( hPieceMask[index] != NULL ) {
\r
2819 DeleteObject( hPieceMask[index] );
\r
2822 hPieceMask[index] = hbm;
\r
2825 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2827 SelectObject( hdc, hbm );
\r
2830 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2831 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2832 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2834 SelectObject( dc1, hPieceMask[index] );
\r
2835 SelectObject( dc2, bm2 );
\r
2836 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2837 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2840 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2841 the piece background and deletes (makes transparent) the rest.
\r
2842 Thanks to that mask, we are free to paint the background with the greates
\r
2843 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2844 We use this, to make gradients and give the pieces a "roundish" look.
\r
2846 SetPieceBackground( hdc, backColor, 2 );
\r
2847 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2851 DeleteObject( bm2 );
\r
2854 SetTextColor( hdc, foreColor );
\r
2855 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2857 SelectObject( hdc, hbm_old );
\r
2859 if( hPieceFace[index] != NULL ) {
\r
2860 DeleteObject( hPieceFace[index] );
\r
2863 hPieceFace[index] = hbm;
\r
2866 static int TranslatePieceToFontPiece( int piece )
\r
2896 case BlackMarshall:
\r
2900 case BlackNightrider:
\r
2906 case BlackUnicorn:
\r
2910 case BlackGrasshopper:
\r
2922 case BlackCardinal:
\r
2929 case WhiteMarshall:
\r
2933 case WhiteNightrider:
\r
2939 case WhiteUnicorn:
\r
2943 case WhiteGrasshopper:
\r
2955 case WhiteCardinal:
\r
2964 void CreatePiecesFromFont()
\r
2967 HDC hdc_window = NULL;
\r
2973 if( fontBitmapSquareSize < 0 ) {
\r
2974 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2978 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2979 fontBitmapSquareSize = -1;
\r
2983 if( fontBitmapSquareSize != squareSize ) {
\r
2984 hdc_window = GetDC( hwndMain );
\r
2985 hdc = CreateCompatibleDC( hdc_window );
\r
2987 if( hPieceFont != NULL ) {
\r
2988 DeleteObject( hPieceFont );
\r
2991 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2992 hPieceMask[i] = NULL;
\r
2993 hPieceFace[i] = NULL;
\r
2999 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
3000 fontHeight = appData.fontPieceSize;
\r
3003 fontHeight = (fontHeight * squareSize) / 100;
\r
3005 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
3007 lf.lfEscapement = 0;
\r
3008 lf.lfOrientation = 0;
\r
3009 lf.lfWeight = FW_NORMAL;
\r
3011 lf.lfUnderline = 0;
\r
3012 lf.lfStrikeOut = 0;
\r
3013 lf.lfCharSet = DEFAULT_CHARSET;
\r
3014 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3015 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3016 lf.lfQuality = PROOF_QUALITY;
\r
3017 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3018 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3019 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3021 hPieceFont = CreateFontIndirect( &lf );
\r
3023 if( hPieceFont == NULL ) {
\r
3024 fontBitmapSquareSize = -2;
\r
3027 /* Setup font-to-piece character table */
\r
3028 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3029 /* No (or wrong) global settings, try to detect the font */
\r
3030 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3032 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3034 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3035 /* DiagramTT* family */
\r
3036 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3038 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3039 /* Fairy symbols */
\r
3040 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3042 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3043 /* Good Companion (Some characters get warped as literal :-( */
\r
3044 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3045 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3046 SetCharTable(pieceToFontChar, s);
\r
3049 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3050 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3054 /* Create bitmaps */
\r
3055 hfont_old = SelectObject( hdc, hPieceFont );
\r
3056 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3057 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3060 SelectObject( hdc, hfont_old );
\r
3062 fontBitmapSquareSize = squareSize;
\r
3066 if( hdc != NULL ) {
\r
3070 if( hdc_window != NULL ) {
\r
3071 ReleaseDC( hwndMain, hdc_window );
\r
3076 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3080 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3081 if (gameInfo.event &&
\r
3082 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3083 strcmp(name, "k80s") == 0) {
\r
3084 strcpy(name, "tim");
\r
3086 return LoadBitmap(hinst, name);
\r
3090 /* Insert a color into the program's logical palette
\r
3091 structure. This code assumes the given color is
\r
3092 the result of the RGB or PALETTERGB macro, and it
\r
3093 knows how those macros work (which is documented).
\r
3096 InsertInPalette(COLORREF color)
\r
3098 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3100 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3101 DisplayFatalError("Too many colors", 0, 1);
\r
3102 pLogPal->palNumEntries--;
\r
3106 pe->peFlags = (char) 0;
\r
3107 pe->peRed = (char) (0xFF & color);
\r
3108 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3109 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3115 InitDrawingColors()
\r
3117 if (pLogPal == NULL) {
\r
3118 /* Allocate enough memory for a logical palette with
\r
3119 * PALETTESIZE entries and set the size and version fields
\r
3120 * of the logical palette structure.
\r
3122 pLogPal = (NPLOGPALETTE)
\r
3123 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3124 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3125 pLogPal->palVersion = 0x300;
\r
3127 pLogPal->palNumEntries = 0;
\r
3129 InsertInPalette(lightSquareColor);
\r
3130 InsertInPalette(darkSquareColor);
\r
3131 InsertInPalette(whitePieceColor);
\r
3132 InsertInPalette(blackPieceColor);
\r
3133 InsertInPalette(highlightSquareColor);
\r
3134 InsertInPalette(premoveHighlightColor);
\r
3136 /* create a logical color palette according the information
\r
3137 * in the LOGPALETTE structure.
\r
3139 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3141 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3142 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3143 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3144 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3145 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3146 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3147 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3148 /* [AS] Force rendering of the font-based pieces */
\r
3149 if( fontBitmapSquareSize > 0 ) {
\r
3150 fontBitmapSquareSize = 0;
\r
3156 BoardWidth(int boardSize, int n)
\r
3157 { /* [HGM] argument n added to allow different width and height */
\r
3158 int lineGap = sizeInfo[boardSize].lineGap;
\r
3160 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3161 lineGap = appData.overrideLineGap;
\r
3164 return (n + 1) * lineGap +
\r
3165 n * sizeInfo[boardSize].squareSize;
\r
3168 /* Respond to board resize by dragging edge */
\r
3170 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3172 BoardSize newSize = NUM_SIZES - 1;
\r
3173 static int recurse = 0;
\r
3174 if (IsIconic(hwndMain)) return;
\r
3175 if (recurse > 0) return;
\r
3177 while (newSize > 0) {
\r
3178 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3179 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3180 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3183 boardSize = newSize;
\r
3184 InitDrawingSizes(boardSize, flags);
\r
3191 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3193 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3194 ChessSquare piece;
\r
3195 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3197 SIZE clockSize, messageSize;
\r
3199 char buf[MSG_SIZ];
\r
3201 HMENU hmenu = GetMenu(hwndMain);
\r
3202 RECT crect, wrect, oldRect;
\r
3204 LOGBRUSH logbrush;
\r
3206 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3207 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3209 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3210 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3212 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3213 oldRect.top = boardY;
\r
3214 oldRect.right = boardX + winWidth;
\r
3215 oldRect.bottom = boardY + winHeight;
\r
3217 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3218 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3219 squareSize = sizeInfo[boardSize].squareSize;
\r
3220 lineGap = sizeInfo[boardSize].lineGap;
\r
3221 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3223 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3224 lineGap = appData.overrideLineGap;
\r
3227 if (tinyLayout != oldTinyLayout) {
\r
3228 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3230 style &= ~WS_SYSMENU;
\r
3231 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3232 "&Minimize\tCtrl+F4");
\r
3234 style |= WS_SYSMENU;
\r
3235 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3237 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3239 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3240 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3241 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3243 DrawMenuBar(hwndMain);
\r
3246 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3247 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3249 /* Get text area sizes */
\r
3250 hdc = GetDC(hwndMain);
\r
3251 if (appData.clockMode) {
\r
3252 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3254 sprintf(buf, "White");
\r
3256 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3257 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3258 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3259 str = "We only care about the height here";
\r
3260 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3261 SelectObject(hdc, oldFont);
\r
3262 ReleaseDC(hwndMain, hdc);
\r
3264 /* Compute where everything goes */
\r
3265 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3266 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3267 logoHeight = 2*clockSize.cy;
\r
3268 leftLogoRect.left = OUTER_MARGIN;
\r
3269 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3270 leftLogoRect.top = OUTER_MARGIN;
\r
3271 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3273 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3274 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3275 rightLogoRect.top = OUTER_MARGIN;
\r
3276 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3279 whiteRect.left = leftLogoRect.right;
\r
3280 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3281 whiteRect.top = OUTER_MARGIN;
\r
3282 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3284 blackRect.right = rightLogoRect.left;
\r
3285 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3286 blackRect.top = whiteRect.top;
\r
3287 blackRect.bottom = whiteRect.bottom;
\r
3289 whiteRect.left = OUTER_MARGIN;
\r
3290 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3291 whiteRect.top = OUTER_MARGIN;
\r
3292 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3294 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3295 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3296 blackRect.top = whiteRect.top;
\r
3297 blackRect.bottom = whiteRect.bottom;
\r
3300 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3301 if (appData.showButtonBar) {
\r
3302 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3303 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3305 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3307 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3308 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3310 boardRect.left = OUTER_MARGIN;
\r
3311 boardRect.right = boardRect.left + boardWidth;
\r
3312 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3313 boardRect.bottom = boardRect.top + boardHeight;
\r
3315 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3316 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3317 oldBoardSize = boardSize;
\r
3318 oldTinyLayout = tinyLayout;
\r
3319 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3320 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3321 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3322 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3323 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3324 winHeight = winH; // without disturbing window attachments
\r
3325 GetWindowRect(hwndMain, &wrect);
\r
3326 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3327 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3329 // [HGM] placement: let attached windows follow size change.
\r
3330 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3331 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3332 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3333 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3334 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3336 /* compensate if menu bar wrapped */
\r
3337 GetClientRect(hwndMain, &crect);
\r
3338 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3339 winHeight += offby;
\r
3341 case WMSZ_TOPLEFT:
\r
3342 SetWindowPos(hwndMain, NULL,
\r
3343 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3344 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3347 case WMSZ_TOPRIGHT:
\r
3349 SetWindowPos(hwndMain, NULL,
\r
3350 wrect.left, wrect.bottom - winHeight,
\r
3351 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3354 case WMSZ_BOTTOMLEFT:
\r
3356 SetWindowPos(hwndMain, NULL,
\r
3357 wrect.right - winWidth, wrect.top,
\r
3358 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3361 case WMSZ_BOTTOMRIGHT:
\r
3365 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3366 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3371 for (i = 0; i < N_BUTTONS; i++) {
\r
3372 if (buttonDesc[i].hwnd != NULL) {
\r
3373 DestroyWindow(buttonDesc[i].hwnd);
\r
3374 buttonDesc[i].hwnd = NULL;
\r
3376 if (appData.showButtonBar) {
\r
3377 buttonDesc[i].hwnd =
\r
3378 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3379 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3380 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3381 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3382 (HMENU) buttonDesc[i].id,
\r
3383 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3385 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3386 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3387 MAKELPARAM(FALSE, 0));
\r
3389 if (buttonDesc[i].id == IDM_Pause)
\r
3390 hwndPause = buttonDesc[i].hwnd;
\r
3391 buttonDesc[i].wndproc = (WNDPROC)
\r
3392 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3395 if (gridPen != NULL) DeleteObject(gridPen);
\r
3396 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3397 if (premovePen != NULL) DeleteObject(premovePen);
\r
3398 if (lineGap != 0) {
\r
3399 logbrush.lbStyle = BS_SOLID;
\r
3400 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3402 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3403 lineGap, &logbrush, 0, NULL);
\r
3404 logbrush.lbColor = highlightSquareColor;
\r
3406 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3407 lineGap, &logbrush, 0, NULL);
\r
3409 logbrush.lbColor = premoveHighlightColor;
\r
3411 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3412 lineGap, &logbrush, 0, NULL);
\r
3414 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3415 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3416 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3417 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3418 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3419 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3420 BOARD_WIDTH * (squareSize + lineGap);
\r
3421 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3423 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3424 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3425 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3426 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3427 lineGap / 2 + (i * (squareSize + lineGap));
\r
3428 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3429 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3430 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3434 /* [HGM] Licensing requirement */
\r
3436 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3439 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3441 GothicPopUp( "", VariantNormal);
\r
3444 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3446 /* Load piece bitmaps for this board size */
\r
3447 for (i=0; i<=2; i++) {
\r
3448 for (piece = WhitePawn;
\r
3449 (int) piece < (int) BlackPawn;
\r
3450 piece = (ChessSquare) ((int) piece + 1)) {
\r
3451 if (pieceBitmap[i][piece] != NULL)
\r
3452 DeleteObject(pieceBitmap[i][piece]);
\r
3456 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3457 // Orthodox Chess pieces
\r
3458 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3459 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3460 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3461 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3462 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3463 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3464 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3465 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3466 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3467 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3468 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3469 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3470 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3471 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3472 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3473 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3474 // in Shogi, Hijack the unused Queen for Lance
\r
3475 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3476 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3477 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3484 if(squareSize <= 72 && squareSize >= 33) {
\r
3485 /* A & C are available in most sizes now */
\r
3486 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3487 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3488 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3489 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3490 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3491 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3492 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3493 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3494 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3495 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3496 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3497 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3498 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3499 } else { // Smirf-like
\r
3500 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3504 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3505 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3506 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3507 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3508 } else { // WinBoard standard
\r
3509 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3516 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3517 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3518 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3519 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3520 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3523 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3524 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3525 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3526 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3529 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3532 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3544 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3545 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3546 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3548 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3549 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3558 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3559 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3560 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3562 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3565 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3566 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3567 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3568 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3569 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3570 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3576 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3577 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3578 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3579 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3580 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3581 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3582 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3583 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3584 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3585 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3586 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3587 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3588 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3589 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3590 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3594 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3595 /* special Shogi support in this size */
\r
3596 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3597 for (piece = WhitePawn;
\r
3598 (int) piece < (int) BlackPawn;
\r
3599 piece = (ChessSquare) ((int) piece + 1)) {
\r
3600 if (pieceBitmap[i][piece] != NULL)
\r
3601 DeleteObject(pieceBitmap[i][piece]);
\r
3604 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3605 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3606 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3607 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3608 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3609 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3610 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3611 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3612 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3613 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3614 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3615 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3618 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3619 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3620 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3621 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3622 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3623 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3624 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3625 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3626 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3627 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3628 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3629 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3632 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3633 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3634 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3635 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3636 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3637 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3638 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3639 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3640 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3641 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3642 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3643 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3651 PieceBitmap(ChessSquare p, int kind)
\r
3653 if ((int) p >= (int) BlackPawn)
\r
3654 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3656 return pieceBitmap[kind][(int) p];
\r
3659 /***************************************************************/
\r
3661 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3662 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3664 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3665 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3669 SquareToPos(int row, int column, int * x, int * y)
\r
3672 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3673 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3675 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3676 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3681 DrawCoordsOnDC(HDC hdc)
\r
3683 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
3684 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
3685 char str[2] = { NULLCHAR, NULLCHAR };
\r
3686 int oldMode, oldAlign, x, y, start, i;
\r
3690 if (!appData.showCoords)
\r
3693 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3695 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3696 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3697 oldAlign = GetTextAlign(hdc);
\r
3698 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3700 y = boardRect.top + lineGap;
\r
3701 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3703 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3704 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3705 str[0] = files[start + i];
\r
3706 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3707 y += squareSize + lineGap;
\r
3710 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3712 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3713 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3714 str[0] = ranks[start + i];
\r
3715 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3716 x += squareSize + lineGap;
\r
3719 SelectObject(hdc, oldBrush);
\r
3720 SetBkMode(hdc, oldMode);
\r
3721 SetTextAlign(hdc, oldAlign);
\r
3722 SelectObject(hdc, oldFont);
\r
3726 DrawGridOnDC(HDC hdc)
\r
3730 if (lineGap != 0) {
\r
3731 oldPen = SelectObject(hdc, gridPen);
\r
3732 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3733 SelectObject(hdc, oldPen);
\r
3737 #define HIGHLIGHT_PEN 0
\r
3738 #define PREMOVE_PEN 1
\r
3741 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3744 HPEN oldPen, hPen;
\r
3745 if (lineGap == 0) return;
\r
3747 x1 = boardRect.left +
\r
3748 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3749 y1 = boardRect.top +
\r
3750 lineGap/2 + y * (squareSize + lineGap);
\r
3752 x1 = boardRect.left +
\r
3753 lineGap/2 + x * (squareSize + lineGap);
\r
3754 y1 = boardRect.top +
\r
3755 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3757 hPen = pen ? premovePen : highlightPen;
\r
3758 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3759 MoveToEx(hdc, x1, y1, NULL);
\r
3760 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3761 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3762 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3763 LineTo(hdc, x1, y1);
\r
3764 SelectObject(hdc, oldPen);
\r
3768 DrawHighlightsOnDC(HDC hdc)
\r
3771 for (i=0; i<2; i++) {
\r
3772 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3773 DrawHighlightOnDC(hdc, TRUE,
\r
3774 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3777 for (i=0; i<2; i++) {
\r
3778 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3779 premoveHighlightInfo.sq[i].y >= 0) {
\r
3780 DrawHighlightOnDC(hdc, TRUE,
\r
3781 premoveHighlightInfo.sq[i].x,
\r
3782 premoveHighlightInfo.sq[i].y,
\r
3788 /* Note: sqcolor is used only in monoMode */
\r
3789 /* Note that this code is largely duplicated in woptions.c,
\r
3790 function DrawSampleSquare, so that needs to be updated too */
\r
3792 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3794 HBITMAP oldBitmap;
\r
3798 if (appData.blindfold) return;
\r
3800 /* [AS] Use font-based pieces if needed */
\r
3801 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3802 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3803 CreatePiecesFromFont();
\r
3805 if( fontBitmapSquareSize == squareSize ) {
\r
3806 int index = TranslatePieceToFontPiece(piece);
\r
3808 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3812 squareSize, squareSize,
\r
3817 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3821 squareSize, squareSize,
\r
3830 if (appData.monoMode) {
\r
3831 SelectObject(tmphdc, PieceBitmap(piece,
\r
3832 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3833 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3834 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3836 tmpSize = squareSize;
\r
3838 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3839 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3840 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3841 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3842 x += (squareSize - minorSize)>>1;
\r
3843 y += squareSize - minorSize - 2;
\r
3844 tmpSize = minorSize;
\r
3846 if (color || appData.allWhite ) {
\r
3847 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3849 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3850 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3851 if(appData.upsideDown && color==flipView)
\r
3852 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3854 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3855 /* Use black for outline of white pieces */
\r
3856 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3857 if(appData.upsideDown && color==flipView)
\r
3858 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3860 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3862 /* Use square color for details of black pieces */
\r
3863 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3864 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3865 if(appData.upsideDown && !flipView)
\r
3866 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3868 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3870 SelectObject(hdc, oldBrush);
\r
3871 SelectObject(tmphdc, oldBitmap);
\r
3875 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3876 int GetBackTextureMode( int algo )
\r
3878 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3882 case BACK_TEXTURE_MODE_PLAIN:
\r
3883 result = 1; /* Always use identity map */
\r
3885 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3886 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3894 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3895 to handle redraws cleanly (as random numbers would always be different).
\r
3897 VOID RebuildTextureSquareInfo()
\r
3907 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3909 if( liteBackTexture != NULL ) {
\r
3910 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3911 lite_w = bi.bmWidth;
\r
3912 lite_h = bi.bmHeight;
\r
3916 if( darkBackTexture != NULL ) {
\r
3917 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3918 dark_w = bi.bmWidth;
\r
3919 dark_h = bi.bmHeight;
\r
3923 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3924 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3925 if( (col + row) & 1 ) {
\r
3927 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3928 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3929 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3930 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3935 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3936 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3937 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3938 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3945 /* [AS] Arrow highlighting support */
\r
3947 static int A_WIDTH = 5; /* Width of arrow body */
\r
3949 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3950 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3952 static double Sqr( double x )
\r
3957 static int Round( double x )
\r
3959 return (int) (x + 0.5);
\r
3962 /* Draw an arrow between two points using current settings */
\r
3963 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3966 double dx, dy, j, k, x, y;
\r
3968 if( d_x == s_x ) {
\r
3969 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3971 arrow[0].x = s_x + A_WIDTH;
\r
3974 arrow[1].x = s_x + A_WIDTH;
\r
3975 arrow[1].y = d_y - h;
\r
3977 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3978 arrow[2].y = d_y - h;
\r
3983 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3984 arrow[4].y = d_y - h;
\r
3986 arrow[5].x = s_x - A_WIDTH;
\r
3987 arrow[5].y = d_y - h;
\r
3989 arrow[6].x = s_x - A_WIDTH;
\r
3992 else if( d_y == s_y ) {
\r
3993 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3996 arrow[0].y = s_y + A_WIDTH;
\r
3998 arrow[1].x = d_x - w;
\r
3999 arrow[1].y = s_y + A_WIDTH;
\r
4001 arrow[2].x = d_x - w;
\r
4002 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4007 arrow[4].x = d_x - w;
\r
4008 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4010 arrow[5].x = d_x - w;
\r
4011 arrow[5].y = s_y - A_WIDTH;
\r
4014 arrow[6].y = s_y - A_WIDTH;
\r
4017 /* [AS] Needed a lot of paper for this! :-) */
\r
4018 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4019 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4021 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4023 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4028 arrow[0].x = Round(x - j);
\r
4029 arrow[0].y = Round(y + j*dx);
\r
4031 arrow[1].x = Round(x + j);
\r
4032 arrow[1].y = Round(y - j*dx);
\r
4035 x = (double) d_x - k;
\r
4036 y = (double) d_y - k*dy;
\r
4039 x = (double) d_x + k;
\r
4040 y = (double) d_y + k*dy;
\r
4043 arrow[2].x = Round(x + j);
\r
4044 arrow[2].y = Round(y - j*dx);
\r
4046 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4047 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4052 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4053 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4055 arrow[6].x = Round(x - j);
\r
4056 arrow[6].y = Round(y + j*dx);
\r
4059 Polygon( hdc, arrow, 7 );
\r
4062 /* [AS] Draw an arrow between two squares */
\r
4063 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4065 int s_x, s_y, d_x, d_y;
\r
4072 if( s_col == d_col && s_row == d_row ) {
\r
4076 /* Get source and destination points */
\r
4077 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4078 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4081 d_y += squareSize / 4;
\r
4083 else if( d_y < s_y ) {
\r
4084 d_y += 3 * squareSize / 4;
\r
4087 d_y += squareSize / 2;
\r
4091 d_x += squareSize / 4;
\r
4093 else if( d_x < s_x ) {
\r
4094 d_x += 3 * squareSize / 4;
\r
4097 d_x += squareSize / 2;
\r
4100 s_x += squareSize / 2;
\r
4101 s_y += squareSize / 2;
\r
4103 /* Adjust width */
\r
4104 A_WIDTH = squareSize / 14;
\r
4107 stLB.lbStyle = BS_SOLID;
\r
4108 stLB.lbColor = appData.highlightArrowColor;
\r
4111 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4112 holdpen = SelectObject( hdc, hpen );
\r
4113 hbrush = CreateBrushIndirect( &stLB );
\r
4114 holdbrush = SelectObject( hdc, hbrush );
\r
4116 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4118 SelectObject( hdc, holdpen );
\r
4119 SelectObject( hdc, holdbrush );
\r
4120 DeleteObject( hpen );
\r
4121 DeleteObject( hbrush );
\r
4124 BOOL HasHighlightInfo()
\r
4126 BOOL result = FALSE;
\r
4128 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4129 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4137 BOOL IsDrawArrowEnabled()
\r
4139 BOOL result = FALSE;
\r
4141 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4148 VOID DrawArrowHighlight( HDC hdc )
\r
4150 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4151 DrawArrowBetweenSquares( hdc,
\r
4152 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4153 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4157 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4159 HRGN result = NULL;
\r
4161 if( HasHighlightInfo() ) {
\r
4162 int x1, y1, x2, y2;
\r
4163 int sx, sy, dx, dy;
\r
4165 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4166 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4168 sx = MIN( x1, x2 );
\r
4169 sy = MIN( y1, y2 );
\r
4170 dx = MAX( x1, x2 ) + squareSize;
\r
4171 dy = MAX( y1, y2 ) + squareSize;
\r
4173 result = CreateRectRgn( sx, sy, dx, dy );
\r
4180 Warning: this function modifies the behavior of several other functions.
\r
4182 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4183 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4184 repaint is scattered all over the place, which is not good for features such as
\r
4185 "arrow highlighting" that require a full repaint of the board.
\r
4187 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4188 user interaction, when speed is not so important) but especially to avoid errors
\r
4189 in the displayed graphics.
\r
4191 In such patched places, I always try refer to this function so there is a single
\r
4192 place to maintain knowledge.
\r
4194 To restore the original behavior, just return FALSE unconditionally.
\r
4196 BOOL IsFullRepaintPreferrable()
\r
4198 BOOL result = FALSE;
\r
4200 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4201 /* Arrow may appear on the board */
\r
4209 This function is called by DrawPosition to know whether a full repaint must
\r
4212 Only DrawPosition may directly call this function, which makes use of
\r
4213 some state information. Other function should call DrawPosition specifying
\r
4214 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4216 BOOL DrawPositionNeedsFullRepaint()
\r
4218 BOOL result = FALSE;
\r
4221 Probably a slightly better policy would be to trigger a full repaint
\r
4222 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4223 but animation is fast enough that it's difficult to notice.
\r
4225 if( animInfo.piece == EmptySquare ) {
\r
4226 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4235 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4237 int row, column, x, y, square_color, piece_color;
\r
4238 ChessSquare piece;
\r
4240 HDC texture_hdc = NULL;
\r
4242 /* [AS] Initialize background textures if needed */
\r
4243 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4244 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4245 if( backTextureSquareSize != squareSize
\r
4246 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4247 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4248 backTextureSquareSize = squareSize;
\r
4249 RebuildTextureSquareInfo();
\r
4252 texture_hdc = CreateCompatibleDC( hdc );
\r
4255 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4256 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4258 SquareToPos(row, column, &x, &y);
\r
4260 piece = board[row][column];
\r
4262 square_color = ((column + row) % 2) == 1;
\r
4263 if( gameInfo.variant == VariantXiangqi ) {
\r
4264 square_color = !InPalace(row, column);
\r
4265 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4266 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4268 piece_color = (int) piece < (int) BlackPawn;
\r
4271 /* [HGM] holdings file: light square or black */
\r
4272 if(column == BOARD_LEFT-2) {
\r
4273 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4276 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4280 if(column == BOARD_RGHT + 1 ) {
\r
4281 if( row < gameInfo.holdingsSize )
\r
4284 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4288 if(column == BOARD_LEFT-1 ) /* left align */
\r
4289 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4290 else if( column == BOARD_RGHT) /* right align */
\r
4291 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4293 if (appData.monoMode) {
\r
4294 if (piece == EmptySquare) {
\r
4295 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4296 square_color ? WHITENESS : BLACKNESS);
\r
4298 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4301 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4302 /* [AS] Draw the square using a texture bitmap */
\r
4303 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4304 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4305 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4308 squareSize, squareSize,
\r
4311 backTextureSquareInfo[r][c].mode,
\r
4312 backTextureSquareInfo[r][c].x,
\r
4313 backTextureSquareInfo[r][c].y );
\r
4315 SelectObject( texture_hdc, hbm );
\r
4317 if (piece != EmptySquare) {
\r
4318 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4322 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4324 oldBrush = SelectObject(hdc, brush );
\r
4325 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4326 SelectObject(hdc, oldBrush);
\r
4327 if (piece != EmptySquare)
\r
4328 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4333 if( texture_hdc != NULL ) {
\r
4334 DeleteDC( texture_hdc );
\r
4338 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4339 void fputDW(FILE *f, int x)
\r
4341 fputc(x & 255, f);
\r
4342 fputc(x>>8 & 255, f);
\r
4343 fputc(x>>16 & 255, f);
\r
4344 fputc(x>>24 & 255, f);
\r
4347 #define MAX_CLIPS 200 /* more than enough */
\r
4350 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4352 // HBITMAP bufferBitmap;
\r
4357 int w = 100, h = 50;
\r
4359 if(logo == NULL) return;
\r
4360 // GetClientRect(hwndMain, &Rect);
\r
4361 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4362 // Rect.bottom-Rect.top+1);
\r
4363 tmphdc = CreateCompatibleDC(hdc);
\r
4364 hbm = SelectObject(tmphdc, logo);
\r
4365 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4369 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4370 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4371 SelectObject(tmphdc, hbm);
\r
4376 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4378 static Board lastReq, lastDrawn;
\r
4379 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4380 static int lastDrawnFlipView = 0;
\r
4381 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4382 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4385 HBITMAP bufferBitmap;
\r
4386 HBITMAP oldBitmap;
\r
4388 HRGN clips[MAX_CLIPS];
\r
4389 ChessSquare dragged_piece = EmptySquare;
\r
4391 /* I'm undecided on this - this function figures out whether a full
\r
4392 * repaint is necessary on its own, so there's no real reason to have the
\r
4393 * caller tell it that. I think this can safely be set to FALSE - but
\r
4394 * if we trust the callers not to request full repaints unnessesarily, then
\r
4395 * we could skip some clipping work. In other words, only request a full
\r
4396 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4397 * gamestart and similar) --Hawk
\r
4399 Boolean fullrepaint = repaint;
\r
4401 if( DrawPositionNeedsFullRepaint() ) {
\r
4402 fullrepaint = TRUE;
\r
4405 if (board == NULL) {
\r
4406 if (!lastReqValid) {
\r
4411 CopyBoard(lastReq, board);
\r
4415 if (doingSizing) {
\r
4419 if (IsIconic(hwndMain)) {
\r
4423 if (hdc == NULL) {
\r
4424 hdc = GetDC(hwndMain);
\r
4425 if (!appData.monoMode) {
\r
4426 SelectPalette(hdc, hPal, FALSE);
\r
4427 RealizePalette(hdc);
\r
4431 releaseDC = FALSE;
\r
4434 /* Create some work-DCs */
\r
4435 hdcmem = CreateCompatibleDC(hdc);
\r
4436 tmphdc = CreateCompatibleDC(hdc);
\r
4438 /* If dragging is in progress, we temporarely remove the piece */
\r
4439 /* [HGM] or temporarily decrease count if stacked */
\r
4440 /* !! Moved to before board compare !! */
\r
4441 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4442 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4443 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4444 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4445 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4447 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4448 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4449 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4451 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4454 /* Figure out which squares need updating by comparing the
\r
4455 * newest board with the last drawn board and checking if
\r
4456 * flipping has changed.
\r
4458 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4459 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4460 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4461 if (lastDrawn[row][column] != board[row][column]) {
\r
4462 SquareToPos(row, column, &x, &y);
\r
4463 clips[num_clips++] =
\r
4464 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4468 for (i=0; i<2; i++) {
\r
4469 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4470 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4471 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4472 lastDrawnHighlight.sq[i].y >= 0) {
\r
4473 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4474 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4475 clips[num_clips++] =
\r
4476 CreateRectRgn(x - lineGap, y - lineGap,
\r
4477 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4479 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4480 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4481 clips[num_clips++] =
\r
4482 CreateRectRgn(x - lineGap, y - lineGap,
\r
4483 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4487 for (i=0; i<2; i++) {
\r
4488 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4489 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4490 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4491 lastDrawnPremove.sq[i].y >= 0) {
\r
4492 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4493 lastDrawnPremove.sq[i].x, &x, &y);
\r
4494 clips[num_clips++] =
\r
4495 CreateRectRgn(x - lineGap, y - lineGap,
\r
4496 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4498 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4499 premoveHighlightInfo.sq[i].y >= 0) {
\r
4500 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4501 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4502 clips[num_clips++] =
\r
4503 CreateRectRgn(x - lineGap, y - lineGap,
\r
4504 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4509 fullrepaint = TRUE;
\r
4512 /* Create a buffer bitmap - this is the actual bitmap
\r
4513 * being written to. When all the work is done, we can
\r
4514 * copy it to the real DC (the screen). This avoids
\r
4515 * the problems with flickering.
\r
4517 GetClientRect(hwndMain, &Rect);
\r
4518 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4519 Rect.bottom-Rect.top+1);
\r
4520 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4521 if (!appData.monoMode) {
\r
4522 SelectPalette(hdcmem, hPal, FALSE);
\r
4525 /* Create clips for dragging */
\r
4526 if (!fullrepaint) {
\r
4527 if (dragInfo.from.x >= 0) {
\r
4528 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4529 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4531 if (dragInfo.start.x >= 0) {
\r
4532 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4533 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4535 if (dragInfo.pos.x >= 0) {
\r
4536 x = dragInfo.pos.x - squareSize / 2;
\r
4537 y = dragInfo.pos.y - squareSize / 2;
\r
4538 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4540 if (dragInfo.lastpos.x >= 0) {
\r
4541 x = dragInfo.lastpos.x - squareSize / 2;
\r
4542 y = dragInfo.lastpos.y - squareSize / 2;
\r
4543 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4547 /* Are we animating a move?
\r
4549 * - remove the piece from the board (temporarely)
\r
4550 * - calculate the clipping region
\r
4552 if (!fullrepaint) {
\r
4553 if (animInfo.piece != EmptySquare) {
\r
4554 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4555 x = boardRect.left + animInfo.lastpos.x;
\r
4556 y = boardRect.top + animInfo.lastpos.y;
\r
4557 x2 = boardRect.left + animInfo.pos.x;
\r
4558 y2 = boardRect.top + animInfo.pos.y;
\r
4559 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4560 /* Slight kludge. The real problem is that after AnimateMove is
\r
4561 done, the position on the screen does not match lastDrawn.
\r
4562 This currently causes trouble only on e.p. captures in
\r
4563 atomic, where the piece moves to an empty square and then
\r
4564 explodes. The old and new positions both had an empty square
\r
4565 at the destination, but animation has drawn a piece there and
\r
4566 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4567 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4571 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4572 if (num_clips == 0)
\r
4573 fullrepaint = TRUE;
\r
4575 /* Set clipping on the memory DC */
\r
4576 if (!fullrepaint) {
\r
4577 SelectClipRgn(hdcmem, clips[0]);
\r
4578 for (x = 1; x < num_clips; x++) {
\r
4579 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4580 abort(); // this should never ever happen!
\r
4584 /* Do all the drawing to the memory DC */
\r
4585 if(explodeInfo.radius) { // [HGM] atomic
\r
4587 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4588 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4589 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4590 x += squareSize/2;
\r
4591 y += squareSize/2;
\r
4592 if(!fullrepaint) {
\r
4593 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4594 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4596 DrawGridOnDC(hdcmem);
\r
4597 DrawHighlightsOnDC(hdcmem);
\r
4598 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4599 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4600 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4601 SelectObject(hdcmem, oldBrush);
\r
4603 DrawGridOnDC(hdcmem);
\r
4604 DrawHighlightsOnDC(hdcmem);
\r
4605 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4608 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4609 if(appData.autoLogo) {
\r
4611 switch(gameMode) { // pick logos based on game mode
\r
4612 case IcsObserving:
\r
4613 whiteLogo = second.programLogo; // ICS logo
\r
4614 blackLogo = second.programLogo;
\r
4617 case IcsPlayingWhite:
\r
4618 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4619 blackLogo = second.programLogo; // ICS logo
\r
4621 case IcsPlayingBlack:
\r
4622 whiteLogo = second.programLogo; // ICS logo
\r
4623 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4625 case TwoMachinesPlay:
\r
4626 if(first.twoMachinesColor[0] == 'b') {
\r
4627 whiteLogo = second.programLogo;
\r
4628 blackLogo = first.programLogo;
\r
4631 case MachinePlaysWhite:
\r
4632 blackLogo = userLogo;
\r
4634 case MachinePlaysBlack:
\r
4635 whiteLogo = userLogo;
\r
4636 blackLogo = first.programLogo;
\r
4639 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4640 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4643 if( appData.highlightMoveWithArrow ) {
\r
4644 DrawArrowHighlight(hdcmem);
\r
4647 DrawCoordsOnDC(hdcmem);
\r
4649 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4650 /* to make sure lastDrawn contains what is actually drawn */
\r
4652 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4653 if (dragged_piece != EmptySquare) {
\r
4654 /* [HGM] or restack */
\r
4655 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4656 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4658 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4659 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4660 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4661 x = dragInfo.pos.x - squareSize / 2;
\r
4662 y = dragInfo.pos.y - squareSize / 2;
\r
4663 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4664 ((int) dragged_piece < (int) BlackPawn),
\r
4665 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4668 /* Put the animated piece back into place and draw it */
\r
4669 if (animInfo.piece != EmptySquare) {
\r
4670 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4671 x = boardRect.left + animInfo.pos.x;
\r
4672 y = boardRect.top + animInfo.pos.y;
\r
4673 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4674 ((int) animInfo.piece < (int) BlackPawn),
\r
4675 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4678 /* Release the bufferBitmap by selecting in the old bitmap
\r
4679 * and delete the memory DC
\r
4681 SelectObject(hdcmem, oldBitmap);
\r
4684 /* Set clipping on the target DC */
\r
4685 if (!fullrepaint) {
\r
4686 SelectClipRgn(hdc, clips[0]);
\r
4687 for (x = 1; x < num_clips; x++) {
\r
4688 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4689 abort(); // this should never ever happen!
\r
4693 /* Copy the new bitmap onto the screen in one go.
\r
4694 * This way we avoid any flickering
\r
4696 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4697 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4698 boardRect.right - boardRect.left,
\r
4699 boardRect.bottom - boardRect.top,
\r
4700 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4701 if(saveDiagFlag) {
\r
4702 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4703 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4705 GetObject(bufferBitmap, sizeof(b), &b);
\r
4706 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4707 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4708 bih.biWidth = b.bmWidth;
\r
4709 bih.biHeight = b.bmHeight;
\r
4711 bih.biBitCount = b.bmBitsPixel;
\r
4712 bih.biCompression = 0;
\r
4713 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4714 bih.biXPelsPerMeter = 0;
\r
4715 bih.biYPelsPerMeter = 0;
\r
4716 bih.biClrUsed = 0;
\r
4717 bih.biClrImportant = 0;
\r
4718 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4719 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4720 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4721 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4723 wb = b.bmWidthBytes;
\r
4725 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4726 int k = ((int*) pData)[i];
\r
4727 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4728 if(j >= 16) break;
\r
4730 if(j >= nrColors) nrColors = j+1;
\r
4732 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4734 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4735 for(w=0; w<(wb>>2); w+=2) {
\r
4736 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4737 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4738 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4739 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4740 pData[p++] = m | j<<4;
\r
4742 while(p&3) pData[p++] = 0;
\r
4745 wb = ((wb+31)>>5)<<2;
\r
4747 // write BITMAPFILEHEADER
\r
4748 fprintf(diagFile, "BM");
\r
4749 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4750 fputDW(diagFile, 0);
\r
4751 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4752 // write BITMAPINFOHEADER
\r
4753 fputDW(diagFile, 40);
\r
4754 fputDW(diagFile, b.bmWidth);
\r
4755 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4756 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4757 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4758 fputDW(diagFile, 0);
\r
4759 fputDW(diagFile, 0);
\r
4760 fputDW(diagFile, 0);
\r
4761 fputDW(diagFile, 0);
\r
4762 fputDW(diagFile, 0);
\r
4763 fputDW(diagFile, 0);
\r
4764 // write color table
\r
4766 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4767 // write bitmap data
\r
4768 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4769 fputc(pData[i], diagFile);
\r
4773 SelectObject(tmphdc, oldBitmap);
\r
4775 /* Massive cleanup */
\r
4776 for (x = 0; x < num_clips; x++)
\r
4777 DeleteObject(clips[x]);
\r
4780 DeleteObject(bufferBitmap);
\r
4783 ReleaseDC(hwndMain, hdc);
\r
4785 if (lastDrawnFlipView != flipView) {
\r
4787 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4789 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4792 /* CopyBoard(lastDrawn, board);*/
\r
4793 lastDrawnHighlight = highlightInfo;
\r
4794 lastDrawnPremove = premoveHighlightInfo;
\r
4795 lastDrawnFlipView = flipView;
\r
4796 lastDrawnValid = 1;
\r
4799 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4804 saveDiagFlag = 1; diagFile = f;
\r
4805 HDCDrawPosition(NULL, TRUE, NULL);
\r
4809 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4816 /*---------------------------------------------------------------------------*\
\r
4817 | CLIENT PAINT PROCEDURE
\r
4818 | This is the main event-handler for the WM_PAINT message.
\r
4820 \*---------------------------------------------------------------------------*/
\r
4822 PaintProc(HWND hwnd)
\r
4828 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4829 if (IsIconic(hwnd)) {
\r
4830 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4832 if (!appData.monoMode) {
\r
4833 SelectPalette(hdc, hPal, FALSE);
\r
4834 RealizePalette(hdc);
\r
4836 HDCDrawPosition(hdc, 1, NULL);
\r
4838 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4839 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4840 ETO_CLIPPED|ETO_OPAQUE,
\r
4841 &messageRect, messageText, strlen(messageText), NULL);
\r
4842 SelectObject(hdc, oldFont);
\r
4843 DisplayBothClocks();
\r
4845 EndPaint(hwnd,&ps);
\r
4853 * If the user selects on a border boundary, return -1; if off the board,
\r
4854 * return -2. Otherwise map the event coordinate to the square.
\r
4855 * The offset boardRect.left or boardRect.top must already have been
\r
4856 * subtracted from x.
\r
4858 int EventToSquare(x, limit)
\r
4866 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4868 x /= (squareSize + lineGap);
\r
4880 DropEnable dropEnables[] = {
\r
4881 { 'P', DP_Pawn, "Pawn" },
\r
4882 { 'N', DP_Knight, "Knight" },
\r
4883 { 'B', DP_Bishop, "Bishop" },
\r
4884 { 'R', DP_Rook, "Rook" },
\r
4885 { 'Q', DP_Queen, "Queen" },
\r
4889 SetupDropMenu(HMENU hmenu)
\r
4891 int i, count, enable;
\r
4893 extern char white_holding[], black_holding[];
\r
4894 char item[MSG_SIZ];
\r
4896 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4897 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4898 dropEnables[i].piece);
\r
4900 while (p && *p++ == dropEnables[i].piece) count++;
\r
4901 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4902 enable = count > 0 || !appData.testLegality
\r
4903 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4904 && !appData.icsActive);
\r
4905 ModifyMenu(hmenu, dropEnables[i].command,
\r
4906 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4907 dropEnables[i].command, item);
\r
4911 void DragPieceBegin(int x, int y)
\r
4913 dragInfo.lastpos.x = boardRect.left + x;
\r
4914 dragInfo.lastpos.y = boardRect.top + y;
\r
4915 dragInfo.from.x = fromX;
\r
4916 dragInfo.from.y = fromY;
\r
4917 dragInfo.start = dragInfo.from;
\r
4918 SetCapture(hwndMain);
\r
4921 void DragPieceEnd(int x, int y)
\r
4924 dragInfo.start.x = dragInfo.start.y = -1;
\r
4925 dragInfo.from = dragInfo.start;
\r
4926 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4929 /* Event handler for mouse messages */
\r
4931 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4935 static int recursive = 0;
\r
4937 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4940 if (message == WM_MBUTTONUP) {
\r
4941 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4942 to the middle button: we simulate pressing the left button too!
\r
4944 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4945 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4951 pt.x = LOWORD(lParam);
\r
4952 pt.y = HIWORD(lParam);
\r
4953 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4954 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4955 if (!flipView && y >= 0) {
\r
4956 y = BOARD_HEIGHT - 1 - y;
\r
4958 if (flipView && x >= 0) {
\r
4959 x = BOARD_WIDTH - 1 - x;
\r
4962 switch (message) {
\r
4963 case WM_LBUTTONDOWN:
\r
4964 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4965 if (gameMode == EditPosition) {
\r
4966 SetWhiteToPlayEvent();
\r
4967 } else if (gameMode == IcsPlayingBlack ||
\r
4968 gameMode == MachinePlaysWhite) {
\r
4970 } else if (gameMode == EditGame) {
\r
4971 AdjustClock(flipClock, -1);
\r
4973 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4974 if (gameMode == EditPosition) {
\r
4975 SetBlackToPlayEvent();
\r
4976 } else if (gameMode == IcsPlayingWhite ||
\r
4977 gameMode == MachinePlaysBlack) {
\r
4979 } else if (gameMode == EditGame) {
\r
4980 AdjustClock(!flipClock, -1);
\r
4983 dragInfo.start.x = dragInfo.start.y = -1;
\r
4984 dragInfo.from = dragInfo.start;
\r
4985 if(fromX == -1 && frozen) { // not sure where this is for
\r
4986 fromX = fromY = -1;
\r
4987 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4990 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4991 DrawPosition(TRUE, NULL);
\r
4994 case WM_LBUTTONUP:
\r
4995 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4996 DrawPosition(TRUE, NULL);
\r
4999 case WM_MOUSEMOVE:
\r
5000 if ((appData.animateDragging || appData.highlightDragging)
\r
5001 && (wParam & MK_LBUTTON)
\r
5002 && dragInfo.from.x >= 0)
\r
5004 BOOL full_repaint = FALSE;
\r
5006 if (appData.animateDragging) {
\r
5007 dragInfo.pos = pt;
\r
5009 if (appData.highlightDragging) {
\r
5010 SetHighlights(fromX, fromY, x, y);
\r
5011 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5012 full_repaint = TRUE;
\r
5016 DrawPosition( full_repaint, NULL);
\r
5018 dragInfo.lastpos = dragInfo.pos;
\r
5022 case WM_MOUSEWHEEL: // [DM]
\r
5023 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5024 /* Mouse Wheel is being rolled forward
\r
5025 * Play moves forward
\r
5027 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5028 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5029 /* Mouse Wheel is being rolled backward
\r
5030 * Play moves backward
\r
5032 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5033 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5037 case WM_MBUTTONDOWN:
\r
5038 case WM_RBUTTONDOWN:
\r
5041 fromX = fromY = -1;
\r
5042 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5043 dragInfo.start.x = dragInfo.start.y = -1;
\r
5044 dragInfo.from = dragInfo.start;
\r
5045 dragInfo.lastpos = dragInfo.pos;
\r
5046 if (appData.highlightDragging) {
\r
5047 ClearHighlights();
\r
5050 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5051 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5052 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5053 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5054 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5057 DrawPosition(TRUE, NULL);
\r
5059 switch (gameMode) {
\r
5060 case EditPosition:
\r
5061 case IcsExamining:
\r
5062 if (x < 0 || y < 0) break;
\r
5065 if (message == WM_MBUTTONDOWN) {
\r
5066 buttonCount = 3; /* even if system didn't think so */
\r
5067 if (wParam & MK_SHIFT)
\r
5068 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5070 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5071 } else { /* message == WM_RBUTTONDOWN */
\r
5072 /* Just have one menu, on the right button. Windows users don't
\r
5073 think to try the middle one, and sometimes other software steals
\r
5074 it, or it doesn't really exist. */
\r
5075 if(gameInfo.variant != VariantShogi)
\r
5076 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5078 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5081 case IcsPlayingWhite:
\r
5082 case IcsPlayingBlack:
\r
5084 case MachinePlaysWhite:
\r
5085 case MachinePlaysBlack:
\r
5086 if (appData.testLegality &&
\r
5087 gameInfo.variant != VariantBughouse &&
\r
5088 gameInfo.variant != VariantCrazyhouse) break;
\r
5089 if (x < 0 || y < 0) break;
\r
5092 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5093 SetupDropMenu(hmenu);
\r
5094 MenuPopup(hwnd, pt, hmenu, -1);
\r
5105 /* Preprocess messages for buttons in main window */
\r
5107 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5109 int id = GetWindowLong(hwnd, GWL_ID);
\r
5112 for (i=0; i<N_BUTTONS; i++) {
\r
5113 if (buttonDesc[i].id == id) break;
\r
5115 if (i == N_BUTTONS) return 0;
\r
5116 switch (message) {
\r
5121 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5122 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5129 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5132 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5133 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5134 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5135 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5137 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5139 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5140 PopUpMoveDialog((char)wParam);
\r
5146 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5149 /* Process messages for Promotion dialog box */
\r
5151 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5155 switch (message) {
\r
5156 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5157 /* Center the dialog over the application window */
\r
5158 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5159 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5160 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5161 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5162 SW_SHOW : SW_HIDE);
\r
5163 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5164 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5165 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5166 PieceToChar(WhiteAngel) != '~') ||
\r
5167 (PieceToChar(BlackAngel) >= 'A' &&
\r
5168 PieceToChar(BlackAngel) != '~') ) ?
\r
5169 SW_SHOW : SW_HIDE);
\r
5170 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5171 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5172 PieceToChar(WhiteMarshall) != '~') ||
\r
5173 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5174 PieceToChar(BlackMarshall) != '~') ) ?
\r
5175 SW_SHOW : SW_HIDE);
\r
5176 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5177 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5178 gameInfo.variant != VariantShogi ?
\r
5179 SW_SHOW : SW_HIDE);
\r
5180 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5181 gameInfo.variant != VariantShogi ?
\r
5182 SW_SHOW : SW_HIDE);
\r
5183 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5184 gameInfo.variant == VariantShogi ?
\r
5185 SW_SHOW : SW_HIDE);
\r
5186 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5187 gameInfo.variant == VariantShogi ?
\r
5188 SW_SHOW : SW_HIDE);
\r
5189 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5190 gameInfo.variant == VariantSuper ?
\r
5191 SW_SHOW : SW_HIDE);
\r
5194 case WM_COMMAND: /* message: received a command */
\r
5195 switch (LOWORD(wParam)) {
\r
5197 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5198 ClearHighlights();
\r
5199 DrawPosition(FALSE, NULL);
\r
5202 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5205 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5208 promoChar = PieceToChar(BlackRook);
\r
5211 promoChar = PieceToChar(BlackBishop);
\r
5213 case PB_Chancellor:
\r
5214 promoChar = PieceToChar(BlackMarshall);
\r
5216 case PB_Archbishop:
\r
5217 promoChar = PieceToChar(BlackAngel);
\r
5220 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5225 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5226 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5227 only show the popup when we are already sure the move is valid or
\r
5228 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5229 will figure out it is a promotion from the promoChar. */
\r
5230 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5231 fromX = fromY = -1;
\r
5232 if (!appData.highlightLastMove) {
\r
5233 ClearHighlights();
\r
5234 DrawPosition(FALSE, NULL);
\r
5241 /* Pop up promotion dialog */
\r
5243 PromotionPopup(HWND hwnd)
\r
5247 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5248 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5249 hwnd, (DLGPROC)lpProc);
\r
5250 FreeProcInstance(lpProc);
\r
5256 DrawPosition(TRUE, NULL);
\r
5257 PromotionPopup(hwndMain);
\r
5260 /* Toggle ShowThinking */
\r
5262 ToggleShowThinking()
\r
5264 appData.showThinking = !appData.showThinking;
\r
5265 ShowThinkingEvent();
\r
5269 LoadGameDialog(HWND hwnd, char* title)
\r
5273 char fileTitle[MSG_SIZ];
\r
5274 f = OpenFileDialog(hwnd, "rb", "",
\r
5275 appData.oldSaveStyle ? "gam" : "pgn",
\r
5277 title, &number, fileTitle, NULL);
\r
5279 cmailMsgLoaded = FALSE;
\r
5280 if (number == 0) {
\r
5281 int error = GameListBuild(f);
\r
5283 DisplayError("Cannot build game list", error);
\r
5284 } else if (!ListEmpty(&gameList) &&
\r
5285 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5286 GameListPopUp(f, fileTitle);
\r
5289 GameListDestroy();
\r
5292 LoadGame(f, number, fileTitle, FALSE);
\r
5296 int get_term_width()
\r
5301 HFONT hfont, hold_font;
\r
5306 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5310 // get the text metrics
\r
5311 hdc = GetDC(hText);
\r
5312 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5313 if (consoleCF.dwEffects & CFE_BOLD)
\r
5314 lf.lfWeight = FW_BOLD;
\r
5315 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5316 lf.lfItalic = TRUE;
\r
5317 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5318 lf.lfStrikeOut = TRUE;
\r
5319 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5320 lf.lfUnderline = TRUE;
\r
5321 hfont = CreateFontIndirect(&lf);
\r
5322 hold_font = SelectObject(hdc, hfont);
\r
5323 GetTextMetrics(hdc, &tm);
\r
5324 SelectObject(hdc, hold_font);
\r
5325 DeleteObject(hfont);
\r
5326 ReleaseDC(hText, hdc);
\r
5328 // get the rectangle
\r
5329 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5331 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5334 void UpdateICSWidth(HWND hText)
\r
5336 LONG old_width, new_width;
\r
5338 new_width = get_term_width(hText, FALSE);
\r
5339 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5340 if (new_width != old_width)
\r
5342 ics_update_width(new_width);
\r
5343 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5348 ChangedConsoleFont()
\r
5351 CHARRANGE tmpsel, sel;
\r
5352 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5353 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5354 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5357 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5358 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5359 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5360 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5361 * size. This was undocumented in the version of MSVC++ that I had
\r
5362 * when I wrote the code, but is apparently documented now.
\r
5364 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5365 cfmt.bCharSet = f->lf.lfCharSet;
\r
5366 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5367 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5368 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5369 /* Why are the following seemingly needed too? */
\r
5370 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5371 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5372 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5374 tmpsel.cpMax = -1; /*999999?*/
\r
5375 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5376 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5377 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5378 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5380 paraf.cbSize = sizeof(paraf);
\r
5381 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5382 paraf.dxStartIndent = 0;
\r
5383 paraf.dxOffset = WRAP_INDENT;
\r
5384 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5385 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5386 UpdateICSWidth(hText);
\r
5389 /*---------------------------------------------------------------------------*\
\r
5391 * Window Proc for main window
\r
5393 \*---------------------------------------------------------------------------*/
\r
5395 /* Process messages for main window, etc. */
\r
5397 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5400 int wmId, wmEvent;
\r
5404 char fileTitle[MSG_SIZ];
\r
5405 char buf[MSG_SIZ];
\r
5406 static SnapData sd;
\r
5408 switch (message) {
\r
5410 case WM_PAINT: /* message: repaint portion of window */
\r
5414 case WM_ERASEBKGND:
\r
5415 if (IsIconic(hwnd)) {
\r
5416 /* Cheat; change the message */
\r
5417 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5419 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5423 case WM_LBUTTONDOWN:
\r
5424 case WM_MBUTTONDOWN:
\r
5425 case WM_RBUTTONDOWN:
\r
5426 case WM_LBUTTONUP:
\r
5427 case WM_MBUTTONUP:
\r
5428 case WM_RBUTTONUP:
\r
5429 case WM_MOUSEMOVE:
\r
5430 case WM_MOUSEWHEEL:
\r
5431 MouseEvent(hwnd, message, wParam, lParam);
\r
5434 JAWS_KB_NAVIGATION
\r
5438 JAWS_ALT_INTERCEPT
\r
5440 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5441 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5442 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5443 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5445 SendMessage(h, message, wParam, lParam);
\r
5446 } else if(lParam != KF_REPEAT) {
\r
5447 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5448 PopUpMoveDialog((char)wParam);
\r
5449 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5450 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5455 case WM_PALETTECHANGED:
\r
5456 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5458 HDC hdc = GetDC(hwndMain);
\r
5459 SelectPalette(hdc, hPal, TRUE);
\r
5460 nnew = RealizePalette(hdc);
\r
5462 paletteChanged = TRUE;
\r
5463 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5465 ReleaseDC(hwnd, hdc);
\r
5469 case WM_QUERYNEWPALETTE:
\r
5470 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5472 HDC hdc = GetDC(hwndMain);
\r
5473 paletteChanged = FALSE;
\r
5474 SelectPalette(hdc, hPal, FALSE);
\r
5475 nnew = RealizePalette(hdc);
\r
5477 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5479 ReleaseDC(hwnd, hdc);
\r
5484 case WM_COMMAND: /* message: command from application menu */
\r
5485 wmId = LOWORD(wParam);
\r
5486 wmEvent = HIWORD(wParam);
\r
5491 SAY("new game enter a move to play against the computer with white");
\r
5494 case IDM_NewGameFRC:
\r
5495 if( NewGameFRC() == 0 ) {
\r
5500 case IDM_NewVariant:
\r
5501 NewVariantPopup(hwnd);
\r
5504 case IDM_LoadGame:
\r
5505 LoadGameDialog(hwnd, "Load Game from File");
\r
5508 case IDM_LoadNextGame:
\r
5512 case IDM_LoadPrevGame:
\r
5516 case IDM_ReloadGame:
\r
5520 case IDM_LoadPosition:
\r
5521 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5522 Reset(FALSE, TRUE);
\r
5525 f = OpenFileDialog(hwnd, "rb", "",
\r
5526 appData.oldSaveStyle ? "pos" : "fen",
\r
5528 "Load Position from File", &number, fileTitle, NULL);
\r
5530 LoadPosition(f, number, fileTitle);
\r
5534 case IDM_LoadNextPosition:
\r
5535 ReloadPosition(1);
\r
5538 case IDM_LoadPrevPosition:
\r
5539 ReloadPosition(-1);
\r
5542 case IDM_ReloadPosition:
\r
5543 ReloadPosition(0);
\r
5546 case IDM_SaveGame:
\r
5547 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5548 f = OpenFileDialog(hwnd, "a", defName,
\r
5549 appData.oldSaveStyle ? "gam" : "pgn",
\r
5551 "Save Game to File", NULL, fileTitle, NULL);
\r
5553 SaveGame(f, 0, "");
\r
5557 case IDM_SavePosition:
\r
5558 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5559 f = OpenFileDialog(hwnd, "a", defName,
\r
5560 appData.oldSaveStyle ? "pos" : "fen",
\r
5562 "Save Position to File", NULL, fileTitle, NULL);
\r
5564 SavePosition(f, 0, "");
\r
5568 case IDM_SaveDiagram:
\r
5569 defName = "diagram";
\r
5570 f = OpenFileDialog(hwnd, "wb", defName,
\r
5573 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5579 case IDM_CopyGame:
\r
5580 CopyGameToClipboard();
\r
5583 case IDM_PasteGame:
\r
5584 PasteGameFromClipboard();
\r
5587 case IDM_CopyGameListToClipboard:
\r
5588 CopyGameListToClipboard();
\r
5591 /* [AS] Autodetect FEN or PGN data */
\r
5592 case IDM_PasteAny:
\r
5593 PasteGameOrFENFromClipboard();
\r
5596 /* [AS] Move history */
\r
5597 case IDM_ShowMoveHistory:
\r
5598 if( MoveHistoryIsUp() ) {
\r
5599 MoveHistoryPopDown();
\r
5602 MoveHistoryPopUp();
\r
5606 /* [AS] Eval graph */
\r
5607 case IDM_ShowEvalGraph:
\r
5608 if( EvalGraphIsUp() ) {
\r
5609 EvalGraphPopDown();
\r
5613 SetFocus(hwndMain);
\r
5617 /* [AS] Engine output */
\r
5618 case IDM_ShowEngineOutput:
\r
5619 if( EngineOutputIsUp() ) {
\r
5620 EngineOutputPopDown();
\r
5623 EngineOutputPopUp();
\r
5627 /* [AS] User adjudication */
\r
5628 case IDM_UserAdjudication_White:
\r
5629 UserAdjudicationEvent( +1 );
\r
5632 case IDM_UserAdjudication_Black:
\r
5633 UserAdjudicationEvent( -1 );
\r
5636 case IDM_UserAdjudication_Draw:
\r
5637 UserAdjudicationEvent( 0 );
\r
5640 /* [AS] Game list options dialog */
\r
5641 case IDM_GameListOptions:
\r
5642 GameListOptions();
\r
5649 case IDM_CopyPosition:
\r
5650 CopyFENToClipboard();
\r
5653 case IDM_PastePosition:
\r
5654 PasteFENFromClipboard();
\r
5657 case IDM_MailMove:
\r
5661 case IDM_ReloadCMailMsg:
\r
5662 Reset(TRUE, TRUE);
\r
5663 ReloadCmailMsgEvent(FALSE);
\r
5666 case IDM_Minimize:
\r
5667 ShowWindow(hwnd, SW_MINIMIZE);
\r
5674 case IDM_MachineWhite:
\r
5675 MachineWhiteEvent();
\r
5677 * refresh the tags dialog only if it's visible
\r
5679 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5681 tags = PGNTags(&gameInfo);
\r
5682 TagsPopUp(tags, CmailMsg());
\r
5685 SAY("computer starts playing white");
\r
5688 case IDM_MachineBlack:
\r
5689 MachineBlackEvent();
\r
5691 * refresh the tags dialog only if it's visible
\r
5693 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5695 tags = PGNTags(&gameInfo);
\r
5696 TagsPopUp(tags, CmailMsg());
\r
5699 SAY("computer starts playing black");
\r
5702 case IDM_TwoMachines:
\r
5703 TwoMachinesEvent();
\r
5705 * refresh the tags dialog only if it's visible
\r
5707 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5709 tags = PGNTags(&gameInfo);
\r
5710 TagsPopUp(tags, CmailMsg());
\r
5713 SAY("programs start playing each other");
\r
5716 case IDM_AnalysisMode:
\r
5717 if (!first.analysisSupport) {
\r
5718 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5719 DisplayError(buf, 0);
\r
5721 SAY("analyzing current position");
\r
5722 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5723 if (appData.icsActive) {
\r
5724 if (gameMode != IcsObserving) {
\r
5725 sprintf(buf, "You are not observing a game");
\r
5726 DisplayError(buf, 0);
\r
5727 /* secure check */
\r
5728 if (appData.icsEngineAnalyze) {
\r
5729 if (appData.debugMode)
\r
5730 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5731 ExitAnalyzeMode();
\r
5737 /* if enable, user want disable icsEngineAnalyze */
\r
5738 if (appData.icsEngineAnalyze) {
\r
5739 ExitAnalyzeMode();
\r
5743 appData.icsEngineAnalyze = TRUE;
\r
5744 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5747 if (!appData.showThinking) ToggleShowThinking();
\r
5748 AnalyzeModeEvent();
\r
5752 case IDM_AnalyzeFile:
\r
5753 if (!first.analysisSupport) {
\r
5754 char buf[MSG_SIZ];
\r
5755 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5756 DisplayError(buf, 0);
\r
5758 if (!appData.showThinking) ToggleShowThinking();
\r
5759 AnalyzeFileEvent();
\r
5760 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5761 AnalysisPeriodicEvent(1);
\r
5765 case IDM_IcsClient:
\r
5769 case IDM_EditGame:
\r
5774 case IDM_EditPosition:
\r
5775 EditPositionEvent();
\r
5776 SAY("to set up a position type a FEN");
\r
5779 case IDM_Training:
\r
5783 case IDM_ShowGameList:
\r
5784 ShowGameListProc();
\r
5787 case IDM_EditTags:
\r
5791 case IDM_EditComment:
\r
5792 if (commentUp && editComment) {
\r
5795 EditCommentEvent();
\r
5815 case IDM_CallFlag:
\r
5835 case IDM_StopObserving:
\r
5836 StopObservingEvent();
\r
5839 case IDM_StopExamining:
\r
5840 StopExaminingEvent();
\r
5843 case IDM_TypeInMove:
\r
5844 PopUpMoveDialog('\000');
\r
5847 case IDM_TypeInName:
\r
5848 PopUpNameDialog('\000');
\r
5851 case IDM_Backward:
\r
5853 SetFocus(hwndMain);
\r
5860 SetFocus(hwndMain);
\r
5865 SetFocus(hwndMain);
\r
5870 SetFocus(hwndMain);
\r
5877 case IDM_TruncateGame:
\r
5878 TruncateGameEvent();
\r
5885 case IDM_RetractMove:
\r
5886 RetractMoveEvent();
\r
5889 case IDM_FlipView:
\r
5890 flipView = !flipView;
\r
5891 DrawPosition(FALSE, NULL);
\r
5894 case IDM_FlipClock:
\r
5895 flipClock = !flipClock;
\r
5896 DisplayBothClocks();
\r
5897 DrawPosition(FALSE, NULL);
\r
5900 case IDM_MuteSounds:
\r
5901 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5902 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5903 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5906 case IDM_GeneralOptions:
\r
5907 GeneralOptionsPopup(hwnd);
\r
5908 DrawPosition(TRUE, NULL);
\r
5911 case IDM_BoardOptions:
\r
5912 BoardOptionsPopup(hwnd);
\r
5915 case IDM_EnginePlayOptions:
\r
5916 EnginePlayOptionsPopup(hwnd);
\r
5919 case IDM_Engine1Options:
\r
5920 EngineOptionsPopup(hwnd, &first);
\r
5923 case IDM_Engine2Options:
\r
5924 EngineOptionsPopup(hwnd, &second);
\r
5927 case IDM_OptionsUCI:
\r
5928 UciOptionsPopup(hwnd);
\r
5931 case IDM_IcsOptions:
\r
5932 IcsOptionsPopup(hwnd);
\r
5936 FontsOptionsPopup(hwnd);
\r
5940 SoundOptionsPopup(hwnd);
\r
5943 case IDM_CommPort:
\r
5944 CommPortOptionsPopup(hwnd);
\r
5947 case IDM_LoadOptions:
\r
5948 LoadOptionsPopup(hwnd);
\r
5951 case IDM_SaveOptions:
\r
5952 SaveOptionsPopup(hwnd);
\r
5955 case IDM_TimeControl:
\r
5956 TimeControlOptionsPopup(hwnd);
\r
5959 case IDM_SaveSettings:
\r
5960 SaveSettings(settingsFileName);
\r
5963 case IDM_SaveSettingsOnExit:
\r
5964 saveSettingsOnExit = !saveSettingsOnExit;
\r
5965 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5966 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5967 MF_CHECKED : MF_UNCHECKED));
\r
5978 case IDM_AboutGame:
\r
5983 appData.debugMode = !appData.debugMode;
\r
5984 if (appData.debugMode) {
\r
5985 char dir[MSG_SIZ];
\r
5986 GetCurrentDirectory(MSG_SIZ, dir);
\r
5987 SetCurrentDirectory(installDir);
\r
5988 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5989 SetCurrentDirectory(dir);
\r
5990 setbuf(debugFP, NULL);
\r
5997 case IDM_HELPCONTENTS:
\r
5998 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5999 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6000 MessageBox (GetFocus(),
\r
6001 "Unable to activate help",
\r
6002 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6006 case IDM_HELPSEARCH:
\r
6007 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6008 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6009 MessageBox (GetFocus(),
\r
6010 "Unable to activate help",
\r
6011 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6015 case IDM_HELPHELP:
\r
6016 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6017 MessageBox (GetFocus(),
\r
6018 "Unable to activate help",
\r
6019 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6024 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6026 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6027 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6028 FreeProcInstance(lpProc);
\r
6031 case IDM_DirectCommand1:
\r
6032 AskQuestionEvent("Direct Command",
\r
6033 "Send to chess program:", "", "1");
\r
6035 case IDM_DirectCommand2:
\r
6036 AskQuestionEvent("Direct Command",
\r
6037 "Send to second chess program:", "", "2");
\r
6040 case EP_WhitePawn:
\r
6041 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6042 fromX = fromY = -1;
\r
6045 case EP_WhiteKnight:
\r
6046 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6047 fromX = fromY = -1;
\r
6050 case EP_WhiteBishop:
\r
6051 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6052 fromX = fromY = -1;
\r
6055 case EP_WhiteRook:
\r
6056 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6057 fromX = fromY = -1;
\r
6060 case EP_WhiteQueen:
\r
6061 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6062 fromX = fromY = -1;
\r
6065 case EP_WhiteFerz:
\r
6066 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6067 fromX = fromY = -1;
\r
6070 case EP_WhiteWazir:
\r
6071 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_WhiteAlfil:
\r
6076 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_WhiteCannon:
\r
6081 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6085 case EP_WhiteCardinal:
\r
6086 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6090 case EP_WhiteMarshall:
\r
6091 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6095 case EP_WhiteKing:
\r
6096 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6100 case EP_BlackPawn:
\r
6101 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6105 case EP_BlackKnight:
\r
6106 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6110 case EP_BlackBishop:
\r
6111 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6115 case EP_BlackRook:
\r
6116 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6120 case EP_BlackQueen:
\r
6121 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6125 case EP_BlackFerz:
\r
6126 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6130 case EP_BlackWazir:
\r
6131 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6132 fromX = fromY = -1;
\r
6135 case EP_BlackAlfil:
\r
6136 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6137 fromX = fromY = -1;
\r
6140 case EP_BlackCannon:
\r
6141 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6142 fromX = fromY = -1;
\r
6145 case EP_BlackCardinal:
\r
6146 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6147 fromX = fromY = -1;
\r
6150 case EP_BlackMarshall:
\r
6151 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6152 fromX = fromY = -1;
\r
6155 case EP_BlackKing:
\r
6156 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6157 fromX = fromY = -1;
\r
6160 case EP_EmptySquare:
\r
6161 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6162 fromX = fromY = -1;
\r
6165 case EP_ClearBoard:
\r
6166 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6167 fromX = fromY = -1;
\r
6171 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6172 fromX = fromY = -1;
\r
6176 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6177 fromX = fromY = -1;
\r
6181 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6182 fromX = fromY = -1;
\r
6186 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6187 fromX = fromY = -1;
\r
6191 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6192 fromX = fromY = -1;
\r
6196 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6197 fromX = fromY = -1;
\r
6201 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6202 fromX = fromY = -1;
\r
6206 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6207 fromX = fromY = -1;
\r
6211 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6212 fromX = fromY = -1;
\r
6216 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6222 case CLOCK_TIMER_ID:
\r
6223 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6224 clockTimerEvent = 0;
\r
6225 DecrementClocks(); /* call into back end */
\r
6227 case LOAD_GAME_TIMER_ID:
\r
6228 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6229 loadGameTimerEvent = 0;
\r
6230 AutoPlayGameLoop(); /* call into back end */
\r
6232 case ANALYSIS_TIMER_ID:
\r
6233 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6234 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6235 AnalysisPeriodicEvent(0);
\r
6237 KillTimer(hwnd, analysisTimerEvent);
\r
6238 analysisTimerEvent = 0;
\r
6241 case DELAYED_TIMER_ID:
\r
6242 KillTimer(hwnd, delayedTimerEvent);
\r
6243 delayedTimerEvent = 0;
\r
6244 delayedTimerCallback();
\r
6249 case WM_USER_Input:
\r
6250 InputEvent(hwnd, message, wParam, lParam);
\r
6253 /* [AS] Also move "attached" child windows */
\r
6254 case WM_WINDOWPOSCHANGING:
\r
6256 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6257 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6259 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6260 /* Window is moving */
\r
6263 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6264 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6265 rcMain.right = boardX + winWidth;
\r
6266 rcMain.top = boardY;
\r
6267 rcMain.bottom = boardY + winHeight;
\r
6269 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6270 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6271 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6272 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6273 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6280 /* [AS] Snapping */
\r
6281 case WM_ENTERSIZEMOVE:
\r
6282 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6283 if (hwnd == hwndMain) {
\r
6284 doingSizing = TRUE;
\r
6287 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6291 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6292 if (hwnd == hwndMain) {
\r
6293 lastSizing = wParam;
\r
6298 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6299 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6301 case WM_EXITSIZEMOVE:
\r
6302 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6303 if (hwnd == hwndMain) {
\r
6305 doingSizing = FALSE;
\r
6306 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6307 GetClientRect(hwnd, &client);
\r
6308 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6310 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6312 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6315 case WM_DESTROY: /* message: window being destroyed */
\r
6316 PostQuitMessage(0);
\r
6320 if (hwnd == hwndMain) {
\r
6325 default: /* Passes it on if unprocessed */
\r
6326 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6331 /*---------------------------------------------------------------------------*\
\r
6333 * Misc utility routines
\r
6335 \*---------------------------------------------------------------------------*/
\r
6338 * Decent random number generator, at least not as bad as Windows
\r
6339 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6341 unsigned int randstate;
\r
6346 randstate = randstate * 1664525 + 1013904223;
\r
6347 return (int) randstate & 0x7fffffff;
\r
6351 mysrandom(unsigned int seed)
\r
6358 * returns TRUE if user selects a different color, FALSE otherwise
\r
6362 ChangeColor(HWND hwnd, COLORREF *which)
\r
6364 static BOOL firstTime = TRUE;
\r
6365 static DWORD customColors[16];
\r
6367 COLORREF newcolor;
\r
6372 /* Make initial colors in use available as custom colors */
\r
6373 /* Should we put the compiled-in defaults here instead? */
\r
6375 customColors[i++] = lightSquareColor & 0xffffff;
\r
6376 customColors[i++] = darkSquareColor & 0xffffff;
\r
6377 customColors[i++] = whitePieceColor & 0xffffff;
\r
6378 customColors[i++] = blackPieceColor & 0xffffff;
\r
6379 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6380 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6382 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6383 customColors[i++] = textAttribs[ccl].color;
\r
6385 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6386 firstTime = FALSE;
\r
6389 cc.lStructSize = sizeof(cc);
\r
6390 cc.hwndOwner = hwnd;
\r
6391 cc.hInstance = NULL;
\r
6392 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6393 cc.lpCustColors = (LPDWORD) customColors;
\r
6394 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6396 if (!ChooseColor(&cc)) return FALSE;
\r
6398 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6399 if (newcolor == *which) return FALSE;
\r
6400 *which = newcolor;
\r
6404 InitDrawingColors();
\r
6405 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6410 MyLoadSound(MySound *ms)
\r
6416 if (ms->data) free(ms->data);
\r
6419 switch (ms->name[0]) {
\r
6425 /* System sound from Control Panel. Don't preload here. */
\r
6429 if (ms->name[1] == NULLCHAR) {
\r
6430 /* "!" alone = silence */
\r
6433 /* Builtin wave resource. Error if not found. */
\r
6434 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6435 if (h == NULL) break;
\r
6436 ms->data = (void *)LoadResource(hInst, h);
\r
6437 if (h == NULL) break;
\r
6442 /* .wav file. Error if not found. */
\r
6443 f = fopen(ms->name, "rb");
\r
6444 if (f == NULL) break;
\r
6445 if (fstat(fileno(f), &st) < 0) break;
\r
6446 ms->data = malloc(st.st_size);
\r
6447 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6453 char buf[MSG_SIZ];
\r
6454 sprintf(buf, "Error loading sound %s", ms->name);
\r
6455 DisplayError(buf, GetLastError());
\r
6461 MyPlaySound(MySound *ms)
\r
6463 BOOLEAN ok = FALSE;
\r
6465 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6466 switch (ms->name[0]) {
\r
6468 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6473 /* System sound from Control Panel (deprecated feature).
\r
6474 "$" alone or an unset sound name gets default beep (still in use). */
\r
6475 if (ms->name[1]) {
\r
6476 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6478 if (!ok) ok = MessageBeep(MB_OK);
\r
6481 /* Builtin wave resource, or "!" alone for silence */
\r
6482 if (ms->name[1]) {
\r
6483 if (ms->data == NULL) return FALSE;
\r
6484 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6490 /* .wav file. Error if not found. */
\r
6491 if (ms->data == NULL) return FALSE;
\r
6492 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6495 /* Don't print an error: this can happen innocently if the sound driver
\r
6496 is busy; for instance, if another instance of WinBoard is playing
\r
6497 a sound at about the same time. */
\r
6503 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6506 OPENFILENAME *ofn;
\r
6507 static UINT *number; /* gross that this is static */
\r
6509 switch (message) {
\r
6510 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6511 /* Center the dialog over the application window */
\r
6512 ofn = (OPENFILENAME *) lParam;
\r
6513 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6514 number = (UINT *) ofn->lCustData;
\r
6515 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6519 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6520 return FALSE; /* Allow for further processing */
\r
6523 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6524 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6526 return FALSE; /* Allow for further processing */
\r
6532 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6534 static UINT *number;
\r
6535 OPENFILENAME *ofname;
\r
6538 case WM_INITDIALOG:
\r
6539 ofname = (OPENFILENAME *)lParam;
\r
6540 number = (UINT *)(ofname->lCustData);
\r
6543 ofnot = (OFNOTIFY *)lParam;
\r
6544 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6545 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6554 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6555 char *nameFilt, char *dlgTitle, UINT *number,
\r
6556 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6558 OPENFILENAME openFileName;
\r
6559 char buf1[MSG_SIZ];
\r
6562 if (fileName == NULL) fileName = buf1;
\r
6563 if (defName == NULL) {
\r
6564 strcpy(fileName, "*.");
\r
6565 strcat(fileName, defExt);
\r
6567 strcpy(fileName, defName);
\r
6569 if (fileTitle) strcpy(fileTitle, "");
\r
6570 if (number) *number = 0;
\r
6572 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6573 openFileName.hwndOwner = hwnd;
\r
6574 openFileName.hInstance = (HANDLE) hInst;
\r
6575 openFileName.lpstrFilter = nameFilt;
\r
6576 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6577 openFileName.nMaxCustFilter = 0L;
\r
6578 openFileName.nFilterIndex = 1L;
\r
6579 openFileName.lpstrFile = fileName;
\r
6580 openFileName.nMaxFile = MSG_SIZ;
\r
6581 openFileName.lpstrFileTitle = fileTitle;
\r
6582 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6583 openFileName.lpstrInitialDir = NULL;
\r
6584 openFileName.lpstrTitle = dlgTitle;
\r
6585 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6586 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6587 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6588 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6589 openFileName.nFileOffset = 0;
\r
6590 openFileName.nFileExtension = 0;
\r
6591 openFileName.lpstrDefExt = defExt;
\r
6592 openFileName.lCustData = (LONG) number;
\r
6593 openFileName.lpfnHook = oldDialog ?
\r
6594 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6595 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6597 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6598 GetOpenFileName(&openFileName)) {
\r
6599 /* open the file */
\r
6600 f = fopen(openFileName.lpstrFile, write);
\r
6602 MessageBox(hwnd, "File open failed", NULL,
\r
6603 MB_OK|MB_ICONEXCLAMATION);
\r
6607 int err = CommDlgExtendedError();
\r
6608 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6617 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6619 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6622 * Get the first pop-up menu in the menu template. This is the
\r
6623 * menu that TrackPopupMenu displays.
\r
6625 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6627 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6630 * TrackPopup uses screen coordinates, so convert the
\r
6631 * coordinates of the mouse click to screen coordinates.
\r
6633 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6635 /* Draw and track the floating pop-up menu. */
\r
6636 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6637 pt.x, pt.y, 0, hwnd, NULL);
\r
6639 /* Destroy the menu.*/
\r
6640 DestroyMenu(hmenu);
\r
6645 int sizeX, sizeY, newSizeX, newSizeY;
\r
6647 } ResizeEditPlusButtonsClosure;
\r
6650 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6652 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6656 if (hChild == cl->hText) return TRUE;
\r
6657 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6658 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6659 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6660 ScreenToClient(cl->hDlg, &pt);
\r
6661 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6662 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6666 /* Resize a dialog that has a (rich) edit field filling most of
\r
6667 the top, with a row of buttons below */
\r
6669 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6672 int newTextHeight, newTextWidth;
\r
6673 ResizeEditPlusButtonsClosure cl;
\r
6675 /*if (IsIconic(hDlg)) return;*/
\r
6676 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6678 cl.hdwp = BeginDeferWindowPos(8);
\r
6680 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6681 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6682 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6683 if (newTextHeight < 0) {
\r
6684 newSizeY += -newTextHeight;
\r
6685 newTextHeight = 0;
\r
6687 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6688 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6694 cl.newSizeX = newSizeX;
\r
6695 cl.newSizeY = newSizeY;
\r
6696 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6698 EndDeferWindowPos(cl.hdwp);
\r
6701 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6703 RECT rChild, rParent;
\r
6704 int wChild, hChild, wParent, hParent;
\r
6705 int wScreen, hScreen, xNew, yNew;
\r
6708 /* Get the Height and Width of the child window */
\r
6709 GetWindowRect (hwndChild, &rChild);
\r
6710 wChild = rChild.right - rChild.left;
\r
6711 hChild = rChild.bottom - rChild.top;
\r
6713 /* Get the Height and Width of the parent window */
\r
6714 GetWindowRect (hwndParent, &rParent);
\r
6715 wParent = rParent.right - rParent.left;
\r
6716 hParent = rParent.bottom - rParent.top;
\r
6718 /* Get the display limits */
\r
6719 hdc = GetDC (hwndChild);
\r
6720 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6721 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6722 ReleaseDC(hwndChild, hdc);
\r
6724 /* Calculate new X position, then adjust for screen */
\r
6725 xNew = rParent.left + ((wParent - wChild) /2);
\r
6728 } else if ((xNew+wChild) > wScreen) {
\r
6729 xNew = wScreen - wChild;
\r
6732 /* Calculate new Y position, then adjust for screen */
\r
6734 yNew = rParent.top + ((hParent - hChild) /2);
\r
6737 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6742 } else if ((yNew+hChild) > hScreen) {
\r
6743 yNew = hScreen - hChild;
\r
6746 /* Set it, and return */
\r
6747 return SetWindowPos (hwndChild, NULL,
\r
6748 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6751 /* Center one window over another */
\r
6752 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6754 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6757 /*---------------------------------------------------------------------------*\
\r
6759 * Startup Dialog functions
\r
6761 \*---------------------------------------------------------------------------*/
\r
6763 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6765 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6767 while (*cd != NULL) {
\r
6768 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6774 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6776 char buf1[ARG_MAX];
\r
6779 if (str[0] == '@') {
\r
6780 FILE* f = fopen(str + 1, "r");
\r
6782 DisplayFatalError(str + 1, errno, 2);
\r
6785 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6787 buf1[len] = NULLCHAR;
\r
6791 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6794 char buf[MSG_SIZ];
\r
6795 char *end = strchr(str, '\n');
\r
6796 if (end == NULL) return;
\r
6797 memcpy(buf, str, end - str);
\r
6798 buf[end - str] = NULLCHAR;
\r
6799 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6805 SetStartupDialogEnables(HWND hDlg)
\r
6807 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6808 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6809 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6810 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6811 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6812 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6813 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6814 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6815 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6816 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6817 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6818 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6819 IsDlgButtonChecked(hDlg, OPT_View));
\r
6823 QuoteForFilename(char *filename)
\r
6825 int dquote, space;
\r
6826 dquote = strchr(filename, '"') != NULL;
\r
6827 space = strchr(filename, ' ') != NULL;
\r
6828 if (dquote || space) {
\r
6840 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6842 char buf[MSG_SIZ];
\r
6845 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6846 q = QuoteForFilename(nthcp);
\r
6847 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6848 if (*nthdir != NULLCHAR) {
\r
6849 q = QuoteForFilename(nthdir);
\r
6850 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6852 if (*nthcp == NULLCHAR) {
\r
6853 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6854 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6855 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6856 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6861 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6863 char buf[MSG_SIZ];
\r
6867 switch (message) {
\r
6868 case WM_INITDIALOG:
\r
6869 /* Center the dialog */
\r
6870 CenterWindow (hDlg, GetDesktopWindow());
\r
6871 /* Initialize the dialog items */
\r
6872 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6873 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6874 firstChessProgramNames);
\r
6875 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6876 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6877 secondChessProgramNames);
\r
6878 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6879 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6880 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6881 if (*appData.icsHelper != NULLCHAR) {
\r
6882 char *q = QuoteForFilename(appData.icsHelper);
\r
6883 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6885 if (*appData.icsHost == NULLCHAR) {
\r
6886 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6887 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6888 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6889 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6890 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6893 if (appData.icsActive) {
\r
6894 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6896 else if (appData.noChessProgram) {
\r
6897 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6900 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6903 SetStartupDialogEnables(hDlg);
\r
6907 switch (LOWORD(wParam)) {
\r
6909 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6910 strcpy(buf, "/fcp=");
\r
6911 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6913 ParseArgs(StringGet, &p);
\r
6914 strcpy(buf, "/scp=");
\r
6915 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6917 ParseArgs(StringGet, &p);
\r
6918 appData.noChessProgram = FALSE;
\r
6919 appData.icsActive = FALSE;
\r
6920 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6921 strcpy(buf, "/ics /icshost=");
\r
6922 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6924 ParseArgs(StringGet, &p);
\r
6925 if (appData.zippyPlay) {
\r
6926 strcpy(buf, "/fcp=");
\r
6927 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6929 ParseArgs(StringGet, &p);
\r
6931 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6932 appData.noChessProgram = TRUE;
\r
6933 appData.icsActive = FALSE;
\r
6935 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6936 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6939 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6940 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6942 ParseArgs(StringGet, &p);
\r
6944 EndDialog(hDlg, TRUE);
\r
6951 case IDM_HELPCONTENTS:
\r
6952 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6953 MessageBox (GetFocus(),
\r
6954 "Unable to activate help",
\r
6955 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6960 SetStartupDialogEnables(hDlg);
\r
6968 /*---------------------------------------------------------------------------*\
\r
6970 * About box dialog functions
\r
6972 \*---------------------------------------------------------------------------*/
\r
6974 /* Process messages for "About" dialog box */
\r
6976 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6978 switch (message) {
\r
6979 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6980 /* Center the dialog over the application window */
\r
6981 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6982 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6986 case WM_COMMAND: /* message: received a command */
\r
6987 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6988 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6989 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6997 /*---------------------------------------------------------------------------*\
\r
6999 * Comment Dialog functions
\r
7001 \*---------------------------------------------------------------------------*/
\r
7004 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7006 static HANDLE hwndText = NULL;
\r
7007 int len, newSizeX, newSizeY, flags;
\r
7008 static int sizeX, sizeY;
\r
7013 switch (message) {
\r
7014 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7015 /* Initialize the dialog items */
\r
7016 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7017 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7018 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7019 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7020 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7021 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7022 SetWindowText(hDlg, commentTitle);
\r
7023 if (editComment) {
\r
7024 SetFocus(hwndText);
\r
7026 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7028 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7029 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7030 MAKELPARAM(FALSE, 0));
\r
7031 /* Size and position the dialog */
\r
7032 if (!commentDialog) {
\r
7033 commentDialog = hDlg;
\r
7034 flags = SWP_NOZORDER;
\r
7035 GetClientRect(hDlg, &rect);
\r
7036 sizeX = rect.right;
\r
7037 sizeY = rect.bottom;
\r
7038 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7039 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7040 WINDOWPLACEMENT wp;
\r
7041 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7042 wp.length = sizeof(WINDOWPLACEMENT);
\r
7044 wp.showCmd = SW_SHOW;
\r
7045 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7046 wp.rcNormalPosition.left = commentX;
\r
7047 wp.rcNormalPosition.right = commentX + commentW;
\r
7048 wp.rcNormalPosition.top = commentY;
\r
7049 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7050 SetWindowPlacement(hDlg, &wp);
\r
7052 GetClientRect(hDlg, &rect);
\r
7053 newSizeX = rect.right;
\r
7054 newSizeY = rect.bottom;
\r
7055 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7056 newSizeX, newSizeY);
\r
7063 case WM_COMMAND: /* message: received a command */
\r
7064 switch (LOWORD(wParam)) {
\r
7066 if (editComment) {
\r
7068 /* Read changed options from the dialog box */
\r
7069 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7070 len = GetWindowTextLength(hwndText);
\r
7071 str = (char *) malloc(len + 1);
\r
7072 GetWindowText(hwndText, str, len + 1);
\r
7081 ReplaceComment(commentIndex, str);
\r
7088 case OPT_CancelComment:
\r
7092 case OPT_ClearComment:
\r
7093 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7096 case OPT_EditComment:
\r
7097 EditCommentEvent();
\r
7106 newSizeX = LOWORD(lParam);
\r
7107 newSizeY = HIWORD(lParam);
\r
7108 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7113 case WM_GETMINMAXINFO:
\r
7114 /* Prevent resizing window too small */
\r
7115 mmi = (MINMAXINFO *) lParam;
\r
7116 mmi->ptMinTrackSize.x = 100;
\r
7117 mmi->ptMinTrackSize.y = 100;
\r
7124 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7129 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7131 if (str == NULL) str = "";
\r
7132 p = (char *) malloc(2 * strlen(str) + 2);
\r
7135 if (*str == '\n') *q++ = '\r';
\r
7139 if (commentText != NULL) free(commentText);
\r
7141 commentIndex = index;
\r
7142 commentTitle = title;
\r
7144 editComment = edit;
\r
7146 if (commentDialog) {
\r
7147 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7148 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
7150 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7151 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7152 hwndMain, (DLGPROC)lpProc);
\r
7153 FreeProcInstance(lpProc);
\r
7159 /*---------------------------------------------------------------------------*\
\r
7161 * Type-in move dialog functions
\r
7163 \*---------------------------------------------------------------------------*/
\r
7166 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7168 char move[MSG_SIZ];
\r
7170 ChessMove moveType;
\r
7171 int fromX, fromY, toX, toY;
\r
7174 switch (message) {
\r
7175 case WM_INITDIALOG:
\r
7176 move[0] = (char) lParam;
\r
7177 move[1] = NULLCHAR;
\r
7178 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7179 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7180 SetWindowText(hInput, move);
\r
7182 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7186 switch (LOWORD(wParam)) {
\r
7188 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7189 { int n; Board board;
\r
7191 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7192 EditPositionPasteFEN(move);
\r
7193 EndDialog(hDlg, TRUE);
\r
7196 // [HGM] movenum: allow move number to be typed in any mode
\r
7197 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7199 EndDialog(hDlg, TRUE);
\r
7203 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7204 gameMode != Training) {
\r
7205 DisplayMoveError("Displayed move is not current");
\r
7207 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7208 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7209 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7210 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7211 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7212 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7213 if (gameMode != Training)
\r
7214 forwardMostMove = currentMove;
\r
7215 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7217 DisplayMoveError("Could not parse move");
\r
7220 EndDialog(hDlg, TRUE);
\r
7223 EndDialog(hDlg, FALSE);
\r
7234 PopUpMoveDialog(char firstchar)
\r
7238 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7239 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7240 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7241 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7242 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7243 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7244 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7245 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7246 gameMode == Training) {
\r
7247 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7248 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7249 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7250 FreeProcInstance(lpProc);
\r
7254 /*---------------------------------------------------------------------------*\
\r
7256 * Type-in name dialog functions
\r
7258 \*---------------------------------------------------------------------------*/
\r
7261 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7263 char move[MSG_SIZ];
\r
7266 switch (message) {
\r
7267 case WM_INITDIALOG:
\r
7268 move[0] = (char) lParam;
\r
7269 move[1] = NULLCHAR;
\r
7270 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7271 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7272 SetWindowText(hInput, move);
\r
7274 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7278 switch (LOWORD(wParam)) {
\r
7280 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7281 appData.userName = strdup(move);
\r
7284 EndDialog(hDlg, TRUE);
\r
7287 EndDialog(hDlg, FALSE);
\r
7298 PopUpNameDialog(char firstchar)
\r
7302 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7303 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7304 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7305 FreeProcInstance(lpProc);
\r
7308 /*---------------------------------------------------------------------------*\
\r
7312 \*---------------------------------------------------------------------------*/
\r
7314 /* Nonmodal error box */
\r
7315 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7316 WPARAM wParam, LPARAM lParam);
\r
7319 ErrorPopUp(char *title, char *content)
\r
7323 BOOLEAN modal = hwndMain == NULL;
\r
7341 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7342 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7345 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7347 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7348 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7349 hwndMain, (DLGPROC)lpProc);
\r
7350 FreeProcInstance(lpProc);
\r
7357 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7358 if (errorDialog == NULL) return;
\r
7359 DestroyWindow(errorDialog);
\r
7360 errorDialog = NULL;
\r
7364 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7369 switch (message) {
\r
7370 case WM_INITDIALOG:
\r
7371 GetWindowRect(hDlg, &rChild);
\r
7374 SetWindowPos(hDlg, NULL, rChild.left,
\r
7375 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7376 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7380 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7381 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7382 and it doesn't work when you resize the dialog.
\r
7383 For now, just give it a default position.
\r
7385 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7387 errorDialog = hDlg;
\r
7388 SetWindowText(hDlg, errorTitle);
\r
7389 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7390 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7394 switch (LOWORD(wParam)) {
\r
7397 if (errorDialog == hDlg) errorDialog = NULL;
\r
7398 DestroyWindow(hDlg);
\r
7410 HWND gothicDialog = NULL;
\r
7413 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7417 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7419 switch (message) {
\r
7420 case WM_INITDIALOG:
\r
7421 GetWindowRect(hDlg, &rChild);
\r
7423 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7427 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7428 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7429 and it doesn't work when you resize the dialog.
\r
7430 For now, just give it a default position.
\r
7432 gothicDialog = hDlg;
\r
7433 SetWindowText(hDlg, errorTitle);
\r
7434 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7435 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7439 switch (LOWORD(wParam)) {
\r
7442 if (errorDialog == hDlg) errorDialog = NULL;
\r
7443 DestroyWindow(hDlg);
\r
7455 GothicPopUp(char *title, VariantClass variant)
\r
7458 static char *lastTitle;
\r
7460 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7461 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7463 if(lastTitle != title && gothicDialog != NULL) {
\r
7464 DestroyWindow(gothicDialog);
\r
7465 gothicDialog = NULL;
\r
7467 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7468 title = lastTitle;
\r
7469 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7470 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7471 hwndMain, (DLGPROC)lpProc);
\r
7472 FreeProcInstance(lpProc);
\r
7477 /*---------------------------------------------------------------------------*\
\r
7479 * Ics Interaction console functions
\r
7481 \*---------------------------------------------------------------------------*/
\r
7483 #define HISTORY_SIZE 64
\r
7484 static char *history[HISTORY_SIZE];
\r
7485 int histIn = 0, histP = 0;
\r
7488 SaveInHistory(char *cmd)
\r
7490 if (history[histIn] != NULL) {
\r
7491 free(history[histIn]);
\r
7492 history[histIn] = NULL;
\r
7494 if (*cmd == NULLCHAR) return;
\r
7495 history[histIn] = StrSave(cmd);
\r
7496 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7497 if (history[histIn] != NULL) {
\r
7498 free(history[histIn]);
\r
7499 history[histIn] = NULL;
\r
7505 PrevInHistory(char *cmd)
\r
7508 if (histP == histIn) {
\r
7509 if (history[histIn] != NULL) free(history[histIn]);
\r
7510 history[histIn] = StrSave(cmd);
\r
7512 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7513 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7515 return history[histP];
\r
7521 if (histP == histIn) return NULL;
\r
7522 histP = (histP + 1) % HISTORY_SIZE;
\r
7523 return history[histP];
\r
7530 BOOLEAN immediate;
\r
7531 } IcsTextMenuEntry;
\r
7532 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7533 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7536 ParseIcsTextMenu(char *icsTextMenuString)
\r
7539 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7540 char *p = icsTextMenuString;
\r
7541 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7544 if (e->command != NULL) {
\r
7546 e->command = NULL;
\r
7550 e = icsTextMenuEntry;
\r
7551 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7552 if (*p == ';' || *p == '\n') {
\r
7553 e->item = strdup("-");
\r
7554 e->command = NULL;
\r
7556 } else if (*p == '-') {
\r
7557 e->item = strdup("-");
\r
7558 e->command = NULL;
\r
7562 char *q, *r, *s, *t;
\r
7564 q = strchr(p, ',');
\r
7565 if (q == NULL) break;
\r
7567 r = strchr(q + 1, ',');
\r
7568 if (r == NULL) break;
\r
7570 s = strchr(r + 1, ',');
\r
7571 if (s == NULL) break;
\r
7574 t = strchr(s + 1, c);
\r
7577 t = strchr(s + 1, c);
\r
7579 if (t != NULL) *t = NULLCHAR;
\r
7580 e->item = strdup(p);
\r
7581 e->command = strdup(q + 1);
\r
7582 e->getname = *(r + 1) != '0';
\r
7583 e->immediate = *(s + 1) != '0';
\r
7587 if (t == NULL) break;
\r
7596 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7600 hmenu = LoadMenu(hInst, "TextMenu");
\r
7601 h = GetSubMenu(hmenu, 0);
\r
7603 if (strcmp(e->item, "-") == 0) {
\r
7604 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7606 if (e->item[0] == '|') {
\r
7607 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7608 IDM_CommandX + i, &e->item[1]);
\r
7610 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7619 WNDPROC consoleTextWindowProc;
\r
7622 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7624 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7625 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7629 SetWindowText(hInput, command);
\r
7631 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7633 sel.cpMin = 999999;
\r
7634 sel.cpMax = 999999;
\r
7635 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7640 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7641 if (sel.cpMin == sel.cpMax) {
\r
7642 /* Expand to surrounding word */
\r
7645 tr.chrg.cpMax = sel.cpMin;
\r
7646 tr.chrg.cpMin = --sel.cpMin;
\r
7647 if (sel.cpMin < 0) break;
\r
7648 tr.lpstrText = name;
\r
7649 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7650 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7654 tr.chrg.cpMin = sel.cpMax;
\r
7655 tr.chrg.cpMax = ++sel.cpMax;
\r
7656 tr.lpstrText = name;
\r
7657 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7658 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7661 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7662 MessageBeep(MB_ICONEXCLAMATION);
\r
7666 tr.lpstrText = name;
\r
7667 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7669 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7670 MessageBeep(MB_ICONEXCLAMATION);
\r
7673 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7676 sprintf(buf, "%s %s", command, name);
\r
7677 SetWindowText(hInput, buf);
\r
7678 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7680 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7681 SetWindowText(hInput, buf);
\r
7682 sel.cpMin = 999999;
\r
7683 sel.cpMax = 999999;
\r
7684 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7690 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7695 switch (message) {
\r
7697 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7700 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7703 sel.cpMin = 999999;
\r
7704 sel.cpMax = 999999;
\r
7705 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7706 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7711 if(wParam != '\022') {
\r
7712 if (wParam == '\t') {
\r
7713 if (GetKeyState(VK_SHIFT) < 0) {
\r
7715 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7716 if (buttonDesc[0].hwnd) {
\r
7717 SetFocus(buttonDesc[0].hwnd);
\r
7719 SetFocus(hwndMain);
\r
7723 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7726 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7727 JAWS_DELETE( SetFocus(hInput); )
\r
7728 SendMessage(hInput, message, wParam, lParam);
\r
7731 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7732 case WM_RBUTTONUP:
\r
7733 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7734 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7735 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7738 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7739 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7740 if (sel.cpMin == sel.cpMax) {
\r
7741 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7742 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7744 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7745 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7747 pt.x = LOWORD(lParam);
\r
7748 pt.y = HIWORD(lParam);
\r
7749 MenuPopup(hwnd, pt, hmenu, -1);
\r
7753 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7755 return SendMessage(hInput, message, wParam, lParam);
\r
7756 case WM_MBUTTONDOWN:
\r
7757 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7758 case WM_RBUTTONDOWN:
\r
7759 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7760 /* Move selection here if it was empty */
\r
7762 pt.x = LOWORD(lParam);
\r
7763 pt.y = HIWORD(lParam);
\r
7764 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7765 if (sel.cpMin == sel.cpMax) {
\r
7766 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7767 sel.cpMax = sel.cpMin;
\r
7768 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7770 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7774 switch (LOWORD(wParam)) {
\r
7775 case IDM_QuickPaste:
\r
7777 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7778 if (sel.cpMin == sel.cpMax) {
\r
7779 MessageBeep(MB_ICONEXCLAMATION);
\r
7782 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7783 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7784 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7789 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7792 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7795 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7799 int i = LOWORD(wParam) - IDM_CommandX;
\r
7800 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7801 icsTextMenuEntry[i].command != NULL) {
\r
7802 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7803 icsTextMenuEntry[i].getname,
\r
7804 icsTextMenuEntry[i].immediate);
\r
7812 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7815 WNDPROC consoleInputWindowProc;
\r
7818 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7820 char buf[MSG_SIZ];
\r
7822 static BOOL sendNextChar = FALSE;
\r
7823 static BOOL quoteNextChar = FALSE;
\r
7824 InputSource *is = consoleInputSource;
\r
7828 switch (message) {
\r
7830 if (!appData.localLineEditing || sendNextChar) {
\r
7831 is->buf[0] = (CHAR) wParam;
\r
7833 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7834 sendNextChar = FALSE;
\r
7837 if (quoteNextChar) {
\r
7838 buf[0] = (char) wParam;
\r
7839 buf[1] = NULLCHAR;
\r
7840 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7841 quoteNextChar = FALSE;
\r
7845 case '\r': /* Enter key */
\r
7846 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7847 if (consoleEcho) SaveInHistory(is->buf);
\r
7848 is->buf[is->count++] = '\n';
\r
7849 is->buf[is->count] = NULLCHAR;
\r
7850 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7851 if (consoleEcho) {
\r
7852 ConsoleOutput(is->buf, is->count, TRUE);
\r
7853 } else if (appData.localLineEditing) {
\r
7854 ConsoleOutput("\n", 1, TRUE);
\r
7857 case '\033': /* Escape key */
\r
7858 SetWindowText(hwnd, "");
\r
7859 cf.cbSize = sizeof(CHARFORMAT);
\r
7860 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7861 if (consoleEcho) {
\r
7862 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7864 cf.crTextColor = COLOR_ECHOOFF;
\r
7866 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7867 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7869 case '\t': /* Tab key */
\r
7870 if (GetKeyState(VK_SHIFT) < 0) {
\r
7872 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7875 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7876 if (buttonDesc[0].hwnd) {
\r
7877 SetFocus(buttonDesc[0].hwnd);
\r
7879 SetFocus(hwndMain);
\r
7883 case '\023': /* Ctrl+S */
\r
7884 sendNextChar = TRUE;
\r
7886 case '\021': /* Ctrl+Q */
\r
7887 quoteNextChar = TRUE;
\r
7897 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7898 p = PrevInHistory(buf);
\r
7900 SetWindowText(hwnd, p);
\r
7901 sel.cpMin = 999999;
\r
7902 sel.cpMax = 999999;
\r
7903 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7908 p = NextInHistory();
\r
7910 SetWindowText(hwnd, p);
\r
7911 sel.cpMin = 999999;
\r
7912 sel.cpMax = 999999;
\r
7913 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7919 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7923 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7927 case WM_MBUTTONDOWN:
\r
7928 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7929 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7931 case WM_RBUTTONUP:
\r
7932 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7933 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7934 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7938 hmenu = LoadMenu(hInst, "InputMenu");
\r
7939 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7940 if (sel.cpMin == sel.cpMax) {
\r
7941 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7942 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7944 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7945 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7947 pt.x = LOWORD(lParam);
\r
7948 pt.y = HIWORD(lParam);
\r
7949 MenuPopup(hwnd, pt, hmenu, -1);
\r
7953 switch (LOWORD(wParam)) {
\r
7955 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7957 case IDM_SelectAll:
\r
7959 sel.cpMax = -1; /*999999?*/
\r
7960 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7963 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7966 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7969 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7974 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7977 #define CO_MAX 100000
\r
7978 #define CO_TRIM 1000
\r
7981 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7983 static SnapData sd;
\r
7984 HWND hText, hInput;
\r
7986 static int sizeX, sizeY;
\r
7987 int newSizeX, newSizeY;
\r
7991 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7992 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7994 switch (message) {
\r
7996 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7998 ENLINK *pLink = (ENLINK*)lParam;
\r
7999 if (pLink->msg == WM_LBUTTONUP)
\r
8003 tr.chrg = pLink->chrg;
\r
8004 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8005 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8006 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8007 free(tr.lpstrText);
\r
8011 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8012 hwndConsole = hDlg;
\r
8014 consoleTextWindowProc = (WNDPROC)
\r
8015 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8016 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8017 consoleInputWindowProc = (WNDPROC)
\r
8018 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8019 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8020 Colorize(ColorNormal, TRUE);
\r
8021 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8022 ChangedConsoleFont();
\r
8023 GetClientRect(hDlg, &rect);
\r
8024 sizeX = rect.right;
\r
8025 sizeY = rect.bottom;
\r
8026 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8027 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8028 WINDOWPLACEMENT wp;
\r
8029 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8030 wp.length = sizeof(WINDOWPLACEMENT);
\r
8032 wp.showCmd = SW_SHOW;
\r
8033 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8034 wp.rcNormalPosition.left = wpConsole.x;
\r
8035 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8036 wp.rcNormalPosition.top = wpConsole.y;
\r
8037 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8038 SetWindowPlacement(hDlg, &wp);
\r
8041 // [HGM] Chessknight's change 2004-07-13
\r
8042 else { /* Determine Defaults */
\r
8043 WINDOWPLACEMENT wp;
\r
8044 wpConsole.x = winWidth + 1;
\r
8045 wpConsole.y = boardY;
\r
8046 wpConsole.width = screenWidth - winWidth;
\r
8047 wpConsole.height = winHeight;
\r
8048 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8049 wp.length = sizeof(WINDOWPLACEMENT);
\r
8051 wp.showCmd = SW_SHOW;
\r
8052 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8053 wp.rcNormalPosition.left = wpConsole.x;
\r
8054 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8055 wp.rcNormalPosition.top = wpConsole.y;
\r
8056 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8057 SetWindowPlacement(hDlg, &wp);
\r
8060 // Allow hText to highlight URLs and send notifications on them
\r
8061 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8062 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8063 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8064 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8078 if (IsIconic(hDlg)) break;
\r
8079 newSizeX = LOWORD(lParam);
\r
8080 newSizeY = HIWORD(lParam);
\r
8081 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8082 RECT rectText, rectInput;
\r
8084 int newTextHeight, newTextWidth;
\r
8085 GetWindowRect(hText, &rectText);
\r
8086 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8087 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8088 if (newTextHeight < 0) {
\r
8089 newSizeY += -newTextHeight;
\r
8090 newTextHeight = 0;
\r
8092 SetWindowPos(hText, NULL, 0, 0,
\r
8093 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8094 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8095 pt.x = rectInput.left;
\r
8096 pt.y = rectInput.top + newSizeY - sizeY;
\r
8097 ScreenToClient(hDlg, &pt);
\r
8098 SetWindowPos(hInput, NULL,
\r
8099 pt.x, pt.y, /* needs client coords */
\r
8100 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8101 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8107 case WM_GETMINMAXINFO:
\r
8108 /* Prevent resizing window too small */
\r
8109 mmi = (MINMAXINFO *) lParam;
\r
8110 mmi->ptMinTrackSize.x = 100;
\r
8111 mmi->ptMinTrackSize.y = 100;
\r
8114 /* [AS] Snapping */
\r
8115 case WM_ENTERSIZEMOVE:
\r
8116 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8119 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8122 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8124 case WM_EXITSIZEMOVE:
\r
8125 UpdateICSWidth(hText);
\r
8126 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8129 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8137 if (hwndConsole) return;
\r
8138 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8139 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8144 ConsoleOutput(char* data, int length, int forceVisible)
\r
8149 char buf[CO_MAX+1];
\r
8152 static int delayLF = 0;
\r
8153 CHARRANGE savesel, sel;
\r
8155 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8163 while (length--) {
\r
8171 } else if (*p == '\007') {
\r
8172 MyPlaySound(&sounds[(int)SoundBell]);
\r
8179 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8180 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8181 /* Save current selection */
\r
8182 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8183 exlen = GetWindowTextLength(hText);
\r
8184 /* Find out whether current end of text is visible */
\r
8185 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8186 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8187 /* Trim existing text if it's too long */
\r
8188 if (exlen + (q - buf) > CO_MAX) {
\r
8189 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8192 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8193 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8195 savesel.cpMin -= trim;
\r
8196 savesel.cpMax -= trim;
\r
8197 if (exlen < 0) exlen = 0;
\r
8198 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8199 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8201 /* Append the new text */
\r
8202 sel.cpMin = exlen;
\r
8203 sel.cpMax = exlen;
\r
8204 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8205 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8206 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8207 if (forceVisible || exlen == 0 ||
\r
8208 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8209 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8210 /* Scroll to make new end of text visible if old end of text
\r
8211 was visible or new text is an echo of user typein */
\r
8212 sel.cpMin = 9999999;
\r
8213 sel.cpMax = 9999999;
\r
8214 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8215 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8216 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8217 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8219 if (savesel.cpMax == exlen || forceVisible) {
\r
8220 /* Move insert point to new end of text if it was at the old
\r
8221 end of text or if the new text is an echo of user typein */
\r
8222 sel.cpMin = 9999999;
\r
8223 sel.cpMax = 9999999;
\r
8224 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8226 /* Restore previous selection */
\r
8227 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8229 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8236 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8240 COLORREF oldFg, oldBg;
\r
8244 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8246 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8247 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8248 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8251 rect.right = x + squareSize;
\r
8253 rect.bottom = y + squareSize;
\r
8256 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8257 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8258 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8259 &rect, str, strlen(str), NULL);
\r
8261 (void) SetTextColor(hdc, oldFg);
\r
8262 (void) SetBkColor(hdc, oldBg);
\r
8263 (void) SelectObject(hdc, oldFont);
\r
8267 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8268 RECT *rect, char *color, char *flagFell)
\r
8272 COLORREF oldFg, oldBg;
\r
8275 if (appData.clockMode) {
\r
8277 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8279 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8286 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8287 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8289 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8290 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8292 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8296 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8297 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8298 rect, str, strlen(str), NULL);
\r
8299 if(logoHeight > 0 && appData.clockMode) {
\r
8301 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8302 r.top = rect->top + logoHeight/2;
\r
8303 r.left = rect->left;
\r
8304 r.right = rect->right;
\r
8305 r.bottom = rect->bottom;
\r
8306 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8307 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8308 &r, str, strlen(str), NULL);
\r
8310 (void) SetTextColor(hdc, oldFg);
\r
8311 (void) SetBkColor(hdc, oldBg);
\r
8312 (void) SelectObject(hdc, oldFont);
\r
8317 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8323 if( count <= 0 ) {
\r
8324 if (appData.debugMode) {
\r
8325 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8328 return ERROR_INVALID_USER_BUFFER;
\r
8331 ResetEvent(ovl->hEvent);
\r
8332 ovl->Offset = ovl->OffsetHigh = 0;
\r
8333 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8337 err = GetLastError();
\r
8338 if (err == ERROR_IO_PENDING) {
\r
8339 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8343 err = GetLastError();
\r
8350 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8355 ResetEvent(ovl->hEvent);
\r
8356 ovl->Offset = ovl->OffsetHigh = 0;
\r
8357 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8361 err = GetLastError();
\r
8362 if (err == ERROR_IO_PENDING) {
\r
8363 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8367 err = GetLastError();
\r
8373 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8374 void CheckForInputBufferFull( InputSource * is )
\r
8376 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8377 /* Look for end of line */
\r
8378 char * p = is->buf;
\r
8380 while( p < is->next && *p != '\n' ) {
\r
8384 if( p >= is->next ) {
\r
8385 if (appData.debugMode) {
\r
8386 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8389 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8390 is->count = (DWORD) -1;
\r
8391 is->next = is->buf;
\r
8397 InputThread(LPVOID arg)
\r
8402 is = (InputSource *) arg;
\r
8403 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8404 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8405 while (is->hThread != NULL) {
\r
8406 is->error = DoReadFile(is->hFile, is->next,
\r
8407 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8408 &is->count, &ovl);
\r
8409 if (is->error == NO_ERROR) {
\r
8410 is->next += is->count;
\r
8412 if (is->error == ERROR_BROKEN_PIPE) {
\r
8413 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8416 is->count = (DWORD) -1;
\r
8417 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8422 CheckForInputBufferFull( is );
\r
8424 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8426 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8428 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8431 CloseHandle(ovl.hEvent);
\r
8432 CloseHandle(is->hFile);
\r
8434 if (appData.debugMode) {
\r
8435 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8442 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8444 NonOvlInputThread(LPVOID arg)
\r
8451 is = (InputSource *) arg;
\r
8452 while (is->hThread != NULL) {
\r
8453 is->error = ReadFile(is->hFile, is->next,
\r
8454 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8455 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8456 if (is->error == NO_ERROR) {
\r
8457 /* Change CRLF to LF */
\r
8458 if (is->next > is->buf) {
\r
8460 i = is->count + 1;
\r
8468 if (prev == '\r' && *p == '\n') {
\r
8480 if (is->error == ERROR_BROKEN_PIPE) {
\r
8481 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8484 is->count = (DWORD) -1;
\r
8488 CheckForInputBufferFull( is );
\r
8490 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8492 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8494 if (is->count < 0) break; /* Quit on error */
\r
8496 CloseHandle(is->hFile);
\r
8501 SocketInputThread(LPVOID arg)
\r
8505 is = (InputSource *) arg;
\r
8506 while (is->hThread != NULL) {
\r
8507 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8508 if ((int)is->count == SOCKET_ERROR) {
\r
8509 is->count = (DWORD) -1;
\r
8510 is->error = WSAGetLastError();
\r
8512 is->error = NO_ERROR;
\r
8513 is->next += is->count;
\r
8514 if (is->count == 0 && is->second == is) {
\r
8515 /* End of file on stderr; quit with no message */
\r
8519 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8521 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8523 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8529 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8533 is = (InputSource *) lParam;
\r
8534 if (is->lineByLine) {
\r
8535 /* Feed in lines one by one */
\r
8536 char *p = is->buf;
\r
8538 while (q < is->next) {
\r
8539 if (*q++ == '\n') {
\r
8540 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8545 /* Move any partial line to the start of the buffer */
\r
8547 while (p < is->next) {
\r
8552 if (is->error != NO_ERROR || is->count == 0) {
\r
8553 /* Notify backend of the error. Note: If there was a partial
\r
8554 line at the end, it is not flushed through. */
\r
8555 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8558 /* Feed in the whole chunk of input at once */
\r
8559 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8560 is->next = is->buf;
\r
8564 /*---------------------------------------------------------------------------*\
\r
8566 * Menu enables. Used when setting various modes.
\r
8568 \*---------------------------------------------------------------------------*/
\r
8576 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8578 while (enab->item > 0) {
\r
8579 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8584 Enables gnuEnables[] = {
\r
8585 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8599 Enables icsEnables[] = {
\r
8600 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8607 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8613 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8619 Enables zippyEnables[] = {
\r
8620 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8628 Enables ncpEnables[] = {
\r
8629 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8630 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8631 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8632 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8633 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8634 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8638 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8640 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8651 Enables trainingOnEnables[] = {
\r
8652 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8663 Enables trainingOffEnables[] = {
\r
8664 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8675 /* These modify either ncpEnables or gnuEnables */
\r
8676 Enables cmailEnables[] = {
\r
8677 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8678 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8679 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8680 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8681 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8682 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8683 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8687 Enables machineThinkingEnables[] = {
\r
8688 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8689 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8690 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8691 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8692 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8693 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8694 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8695 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8696 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8697 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8698 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8699 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8700 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8701 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8702 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8706 Enables userThinkingEnables[] = {
\r
8707 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8708 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8709 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8710 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8711 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8712 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8713 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8714 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8715 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8716 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8717 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8718 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8719 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8720 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8721 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8725 /*---------------------------------------------------------------------------*\
\r
8727 * Front-end interface functions exported by XBoard.
\r
8728 * Functions appear in same order as prototypes in frontend.h.
\r
8730 \*---------------------------------------------------------------------------*/
\r
8734 static UINT prevChecked = 0;
\r
8735 static int prevPausing = 0;
\r
8738 if (pausing != prevPausing) {
\r
8739 prevPausing = pausing;
\r
8740 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8741 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8742 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8745 switch (gameMode) {
\r
8746 case BeginningOfGame:
\r
8747 if (appData.icsActive)
\r
8748 nowChecked = IDM_IcsClient;
\r
8749 else if (appData.noChessProgram)
\r
8750 nowChecked = IDM_EditGame;
\r
8752 nowChecked = IDM_MachineBlack;
\r
8754 case MachinePlaysBlack:
\r
8755 nowChecked = IDM_MachineBlack;
\r
8757 case MachinePlaysWhite:
\r
8758 nowChecked = IDM_MachineWhite;
\r
8760 case TwoMachinesPlay:
\r
8761 nowChecked = IDM_TwoMachines;
\r
8764 nowChecked = IDM_AnalysisMode;
\r
8767 nowChecked = IDM_AnalyzeFile;
\r
8770 nowChecked = IDM_EditGame;
\r
8772 case PlayFromGameFile:
\r
8773 nowChecked = IDM_LoadGame;
\r
8775 case EditPosition:
\r
8776 nowChecked = IDM_EditPosition;
\r
8779 nowChecked = IDM_Training;
\r
8781 case IcsPlayingWhite:
\r
8782 case IcsPlayingBlack:
\r
8783 case IcsObserving:
\r
8785 nowChecked = IDM_IcsClient;
\r
8792 if (prevChecked != 0)
\r
8793 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8794 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8795 if (nowChecked != 0)
\r
8796 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8797 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8799 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8800 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8801 MF_BYCOMMAND|MF_ENABLED);
\r
8803 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8804 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8807 prevChecked = nowChecked;
\r
8809 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8810 if (appData.icsActive) {
\r
8811 if (appData.icsEngineAnalyze) {
\r
8812 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8813 MF_BYCOMMAND|MF_CHECKED);
\r
8815 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8816 MF_BYCOMMAND|MF_UNCHECKED);
\r
8824 HMENU hmenu = GetMenu(hwndMain);
\r
8825 SetMenuEnables(hmenu, icsEnables);
\r
8826 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8827 MF_BYPOSITION|MF_ENABLED);
\r
8829 if (appData.zippyPlay) {
\r
8830 SetMenuEnables(hmenu, zippyEnables);
\r
8831 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8832 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8833 MF_BYCOMMAND|MF_ENABLED);
\r
8841 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8847 HMENU hmenu = GetMenu(hwndMain);
\r
8848 SetMenuEnables(hmenu, ncpEnables);
\r
8849 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8850 MF_BYPOSITION|MF_GRAYED);
\r
8851 DrawMenuBar(hwndMain);
\r
8857 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8861 SetTrainingModeOn()
\r
8864 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8865 for (i = 0; i < N_BUTTONS; i++) {
\r
8866 if (buttonDesc[i].hwnd != NULL)
\r
8867 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8872 VOID SetTrainingModeOff()
\r
8875 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8876 for (i = 0; i < N_BUTTONS; i++) {
\r
8877 if (buttonDesc[i].hwnd != NULL)
\r
8878 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8884 SetUserThinkingEnables()
\r
8886 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8890 SetMachineThinkingEnables()
\r
8892 HMENU hMenu = GetMenu(hwndMain);
\r
8893 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8895 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8897 if (gameMode == MachinePlaysBlack) {
\r
8898 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8899 } else if (gameMode == MachinePlaysWhite) {
\r
8900 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8901 } else if (gameMode == TwoMachinesPlay) {
\r
8902 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8908 DisplayTitle(char *str)
\r
8910 char title[MSG_SIZ], *host;
\r
8911 if (str[0] != NULLCHAR) {
\r
8912 strcpy(title, str);
\r
8913 } else if (appData.icsActive) {
\r
8914 if (appData.icsCommPort[0] != NULLCHAR)
\r
8917 host = appData.icsHost;
\r
8918 sprintf(title, "%s: %s", szTitle, host);
\r
8919 } else if (appData.noChessProgram) {
\r
8920 strcpy(title, szTitle);
\r
8922 strcpy(title, szTitle);
\r
8923 strcat(title, ": ");
\r
8924 strcat(title, first.tidy);
\r
8926 SetWindowText(hwndMain, title);
\r
8931 DisplayMessage(char *str1, char *str2)
\r
8935 int remain = MESSAGE_TEXT_MAX - 1;
\r
8938 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8939 messageText[0] = NULLCHAR;
\r
8941 len = strlen(str1);
\r
8942 if (len > remain) len = remain;
\r
8943 strncpy(messageText, str1, len);
\r
8944 messageText[len] = NULLCHAR;
\r
8947 if (*str2 && remain >= 2) {
\r
8949 strcat(messageText, " ");
\r
8952 len = strlen(str2);
\r
8953 if (len > remain) len = remain;
\r
8954 strncat(messageText, str2, len);
\r
8956 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8958 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8962 hdc = GetDC(hwndMain);
\r
8963 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8964 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8965 &messageRect, messageText, strlen(messageText), NULL);
\r
8966 (void) SelectObject(hdc, oldFont);
\r
8967 (void) ReleaseDC(hwndMain, hdc);
\r
8971 DisplayError(char *str, int error)
\r
8973 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8979 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8980 NULL, error, LANG_NEUTRAL,
\r
8981 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8983 sprintf(buf, "%s:\n%s", str, buf2);
\r
8985 ErrorMap *em = errmap;
\r
8986 while (em->err != 0 && em->err != error) em++;
\r
8987 if (em->err != 0) {
\r
8988 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8990 sprintf(buf, "%s:\nError code %d", str, error);
\r
8995 ErrorPopUp("Error", buf);
\r
9000 DisplayMoveError(char *str)
\r
9002 fromX = fromY = -1;
\r
9003 ClearHighlights();
\r
9004 DrawPosition(FALSE, NULL);
\r
9005 if (appData.popupMoveErrors) {
\r
9006 ErrorPopUp("Error", str);
\r
9008 DisplayMessage(str, "");
\r
9009 moveErrorMessageUp = TRUE;
\r
9014 DisplayFatalError(char *str, int error, int exitStatus)
\r
9016 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9018 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9021 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9022 NULL, error, LANG_NEUTRAL,
\r
9023 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9025 sprintf(buf, "%s:\n%s", str, buf2);
\r
9027 ErrorMap *em = errmap;
\r
9028 while (em->err != 0 && em->err != error) em++;
\r
9029 if (em->err != 0) {
\r
9030 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9032 sprintf(buf, "%s:\nError code %d", str, error);
\r
9037 if (appData.debugMode) {
\r
9038 fprintf(debugFP, "%s: %s\n", label, str);
\r
9040 if (appData.popupExitMessage) {
\r
9041 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9042 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9044 ExitEvent(exitStatus);
\r
9049 DisplayInformation(char *str)
\r
9051 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9056 DisplayNote(char *str)
\r
9058 ErrorPopUp("Note", str);
\r
9063 char *title, *question, *replyPrefix;
\r
9068 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9070 static QuestionParams *qp;
\r
9071 char reply[MSG_SIZ];
\r
9074 switch (message) {
\r
9075 case WM_INITDIALOG:
\r
9076 qp = (QuestionParams *) lParam;
\r
9077 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9078 SetWindowText(hDlg, qp->title);
\r
9079 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9080 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9084 switch (LOWORD(wParam)) {
\r
9086 strcpy(reply, qp->replyPrefix);
\r
9087 if (*reply) strcat(reply, " ");
\r
9088 len = strlen(reply);
\r
9089 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9090 strcat(reply, "\n");
\r
9091 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9092 EndDialog(hDlg, TRUE);
\r
9093 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9096 EndDialog(hDlg, FALSE);
\r
9107 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9109 QuestionParams qp;
\r
9113 qp.question = question;
\r
9114 qp.replyPrefix = replyPrefix;
\r
9116 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9117 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9118 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9119 FreeProcInstance(lpProc);
\r
9122 /* [AS] Pick FRC position */
\r
9123 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9125 static int * lpIndexFRC;
\r
9131 case WM_INITDIALOG:
\r
9132 lpIndexFRC = (int *) lParam;
\r
9134 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9136 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9137 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9138 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9139 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9144 switch( LOWORD(wParam) ) {
\r
9146 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9147 EndDialog( hDlg, 0 );
\r
9148 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9151 EndDialog( hDlg, 1 );
\r
9153 case IDC_NFG_Edit:
\r
9154 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9155 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9157 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9160 case IDC_NFG_Random:
\r
9161 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9162 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9175 int index = appData.defaultFrcPosition;
\r
9176 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9178 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9180 if( result == 0 ) {
\r
9181 appData.defaultFrcPosition = index;
\r
9187 /* [AS] Game list options */
\r
9193 static GLT_Item GLT_ItemInfo[] = {
\r
9194 { GLT_EVENT, "Event" },
\r
9195 { GLT_SITE, "Site" },
\r
9196 { GLT_DATE, "Date" },
\r
9197 { GLT_ROUND, "Round" },
\r
9198 { GLT_PLAYERS, "Players" },
\r
9199 { GLT_RESULT, "Result" },
\r
9200 { GLT_WHITE_ELO, "White Rating" },
\r
9201 { GLT_BLACK_ELO, "Black Rating" },
\r
9202 { GLT_TIME_CONTROL,"Time Control" },
\r
9203 { GLT_VARIANT, "Variant" },
\r
9204 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9205 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9209 const char * GLT_FindItem( char id )
\r
9211 const char * result = 0;
\r
9213 GLT_Item * list = GLT_ItemInfo;
\r
9215 while( list->id != 0 ) {
\r
9216 if( list->id == id ) {
\r
9217 result = list->name;
\r
9227 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9229 const char * name = GLT_FindItem( id );
\r
9232 if( index >= 0 ) {
\r
9233 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9236 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9241 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9245 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9248 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9252 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9254 pc = GLT_ALL_TAGS;
\r
9257 if( strchr( tags, *pc ) == 0 ) {
\r
9258 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9263 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9266 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9268 char result = '\0';
\r
9271 GLT_Item * list = GLT_ItemInfo;
\r
9273 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9274 while( list->id != 0 ) {
\r
9275 if( strcmp( list->name, name ) == 0 ) {
\r
9276 result = list->id;
\r
9287 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9289 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9290 int idx2 = idx1 + delta;
\r
9291 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9293 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9296 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9297 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9298 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9299 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9303 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9305 static char glt[64];
\r
9306 static char * lpUserGLT;
\r
9310 case WM_INITDIALOG:
\r
9311 lpUserGLT = (char *) lParam;
\r
9313 strcpy( glt, lpUserGLT );
\r
9315 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9317 /* Initialize list */
\r
9318 GLT_TagsToList( hDlg, glt );
\r
9320 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9325 switch( LOWORD(wParam) ) {
\r
9328 char * pc = lpUserGLT;
\r
9330 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9334 id = GLT_ListItemToTag( hDlg, idx );
\r
9338 } while( id != '\0' );
\r
9340 EndDialog( hDlg, 0 );
\r
9343 EndDialog( hDlg, 1 );
\r
9346 case IDC_GLT_Default:
\r
9347 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9348 GLT_TagsToList( hDlg, glt );
\r
9351 case IDC_GLT_Restore:
\r
9352 strcpy( glt, lpUserGLT );
\r
9353 GLT_TagsToList( hDlg, glt );
\r
9357 GLT_MoveSelection( hDlg, -1 );
\r
9360 case IDC_GLT_Down:
\r
9361 GLT_MoveSelection( hDlg, +1 );
\r
9371 int GameListOptions()
\r
9375 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9377 strcpy( glt, appData.gameListTags );
\r
9379 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9381 if( result == 0 ) {
\r
9382 /* [AS] Memory leak here! */
\r
9383 appData.gameListTags = strdup( glt );
\r
9391 DisplayIcsInteractionTitle(char *str)
\r
9393 char consoleTitle[MSG_SIZ];
\r
9395 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9396 SetWindowText(hwndConsole, consoleTitle);
\r
9400 DrawPosition(int fullRedraw, Board board)
\r
9402 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9405 void NotifyFrontendLogin()
\r
9408 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9414 fromX = fromY = -1;
\r
9415 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9416 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9417 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9418 dragInfo.lastpos = dragInfo.pos;
\r
9419 dragInfo.start.x = dragInfo.start.y = -1;
\r
9420 dragInfo.from = dragInfo.start;
\r
9422 DrawPosition(TRUE, NULL);
\r
9428 CommentPopUp(char *title, char *str)
\r
9430 HWND hwnd = GetActiveWindow();
\r
9431 EitherCommentPopUp(0, title, str, FALSE);
\r
9433 SetActiveWindow(hwnd);
\r
9437 CommentPopDown(void)
\r
9439 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9440 if (commentDialog) {
\r
9441 ShowWindow(commentDialog, SW_HIDE);
\r
9443 commentUp = FALSE;
\r
9447 EditCommentPopUp(int index, char *title, char *str)
\r
9449 EitherCommentPopUp(index, title, str, TRUE);
\r
9456 MyPlaySound(&sounds[(int)SoundMove]);
\r
9459 VOID PlayIcsWinSound()
\r
9461 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9464 VOID PlayIcsLossSound()
\r
9466 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9469 VOID PlayIcsDrawSound()
\r
9471 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9474 VOID PlayIcsUnfinishedSound()
\r
9476 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9482 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9490 consoleEcho = TRUE;
\r
9491 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9492 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9493 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9502 consoleEcho = FALSE;
\r
9503 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9504 /* This works OK: set text and background both to the same color */
\r
9506 cf.crTextColor = COLOR_ECHOOFF;
\r
9507 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9508 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9511 /* No Raw()...? */
\r
9513 void Colorize(ColorClass cc, int continuation)
\r
9515 currentColorClass = cc;
\r
9516 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9517 consoleCF.crTextColor = textAttribs[cc].color;
\r
9518 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9519 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9525 static char buf[MSG_SIZ];
\r
9526 DWORD bufsiz = MSG_SIZ;
\r
9528 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9529 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9531 if (!GetUserName(buf, &bufsiz)) {
\r
9532 /*DisplayError("Error getting user name", GetLastError());*/
\r
9533 strcpy(buf, "User");
\r
9541 static char buf[MSG_SIZ];
\r
9542 DWORD bufsiz = MSG_SIZ;
\r
9544 if (!GetComputerName(buf, &bufsiz)) {
\r
9545 /*DisplayError("Error getting host name", GetLastError());*/
\r
9546 strcpy(buf, "Unknown");
\r
9553 ClockTimerRunning()
\r
9555 return clockTimerEvent != 0;
\r
9561 if (clockTimerEvent == 0) return FALSE;
\r
9562 KillTimer(hwndMain, clockTimerEvent);
\r
9563 clockTimerEvent = 0;
\r
9568 StartClockTimer(long millisec)
\r
9570 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9571 (UINT) millisec, NULL);
\r
9575 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9578 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9580 if(appData.noGUI) return;
\r
9581 hdc = GetDC(hwndMain);
\r
9582 if (!IsIconic(hwndMain)) {
\r
9583 DisplayAClock(hdc, timeRemaining, highlight,
\r
9584 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9586 if (highlight && iconCurrent == iconBlack) {
\r
9587 iconCurrent = iconWhite;
\r
9588 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9589 if (IsIconic(hwndMain)) {
\r
9590 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9593 (void) ReleaseDC(hwndMain, hdc);
\r
9595 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9599 DisplayBlackClock(long timeRemaining, int highlight)
\r
9602 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9604 if(appData.noGUI) return;
\r
9605 hdc = GetDC(hwndMain);
\r
9606 if (!IsIconic(hwndMain)) {
\r
9607 DisplayAClock(hdc, timeRemaining, highlight,
\r
9608 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9610 if (highlight && iconCurrent == iconWhite) {
\r
9611 iconCurrent = iconBlack;
\r
9612 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9613 if (IsIconic(hwndMain)) {
\r
9614 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9617 (void) ReleaseDC(hwndMain, hdc);
\r
9619 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9624 LoadGameTimerRunning()
\r
9626 return loadGameTimerEvent != 0;
\r
9630 StopLoadGameTimer()
\r
9632 if (loadGameTimerEvent == 0) return FALSE;
\r
9633 KillTimer(hwndMain, loadGameTimerEvent);
\r
9634 loadGameTimerEvent = 0;
\r
9639 StartLoadGameTimer(long millisec)
\r
9641 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9642 (UINT) millisec, NULL);
\r
9650 char fileTitle[MSG_SIZ];
\r
9652 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9653 f = OpenFileDialog(hwndMain, "a", defName,
\r
9654 appData.oldSaveStyle ? "gam" : "pgn",
\r
9656 "Save Game to File", NULL, fileTitle, NULL);
\r
9658 SaveGame(f, 0, "");
\r
9665 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9667 if (delayedTimerEvent != 0) {
\r
9668 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9669 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9671 KillTimer(hwndMain, delayedTimerEvent);
\r
9672 delayedTimerEvent = 0;
\r
9673 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9674 delayedTimerCallback();
\r
9676 delayedTimerCallback = cb;
\r
9677 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9678 (UINT) millisec, NULL);
\r
9681 DelayedEventCallback
\r
9684 if (delayedTimerEvent) {
\r
9685 return delayedTimerCallback;
\r
9692 CancelDelayedEvent()
\r
9694 if (delayedTimerEvent) {
\r
9695 KillTimer(hwndMain, delayedTimerEvent);
\r
9696 delayedTimerEvent = 0;
\r
9700 DWORD GetWin32Priority(int nice)
\r
9701 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9703 REALTIME_PRIORITY_CLASS 0x00000100
\r
9704 HIGH_PRIORITY_CLASS 0x00000080
\r
9705 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9706 NORMAL_PRIORITY_CLASS 0x00000020
\r
9707 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9708 IDLE_PRIORITY_CLASS 0x00000040
\r
9710 if (nice < -15) return 0x00000080;
\r
9711 if (nice < 0) return 0x00008000;
\r
9712 if (nice == 0) return 0x00000020;
\r
9713 if (nice < 15) return 0x00004000;
\r
9714 return 0x00000040;
\r
9717 /* Start a child process running the given program.
\r
9718 The process's standard output can be read from "from", and its
\r
9719 standard input can be written to "to".
\r
9720 Exit with fatal error if anything goes wrong.
\r
9721 Returns an opaque pointer that can be used to destroy the process
\r
9725 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9727 #define BUFSIZE 4096
\r
9729 HANDLE hChildStdinRd, hChildStdinWr,
\r
9730 hChildStdoutRd, hChildStdoutWr;
\r
9731 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9732 SECURITY_ATTRIBUTES saAttr;
\r
9734 PROCESS_INFORMATION piProcInfo;
\r
9735 STARTUPINFO siStartInfo;
\r
9737 char buf[MSG_SIZ];
\r
9740 if (appData.debugMode) {
\r
9741 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9746 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9747 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9748 saAttr.bInheritHandle = TRUE;
\r
9749 saAttr.lpSecurityDescriptor = NULL;
\r
9752 * The steps for redirecting child's STDOUT:
\r
9753 * 1. Create anonymous pipe to be STDOUT for child.
\r
9754 * 2. Create a noninheritable duplicate of read handle,
\r
9755 * and close the inheritable read handle.
\r
9758 /* Create a pipe for the child's STDOUT. */
\r
9759 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9760 return GetLastError();
\r
9763 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9764 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9765 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9766 FALSE, /* not inherited */
\r
9767 DUPLICATE_SAME_ACCESS);
\r
9769 return GetLastError();
\r
9771 CloseHandle(hChildStdoutRd);
\r
9774 * The steps for redirecting child's STDIN:
\r
9775 * 1. Create anonymous pipe to be STDIN for child.
\r
9776 * 2. Create a noninheritable duplicate of write handle,
\r
9777 * and close the inheritable write handle.
\r
9780 /* Create a pipe for the child's STDIN. */
\r
9781 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9782 return GetLastError();
\r
9785 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9786 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9787 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9788 FALSE, /* not inherited */
\r
9789 DUPLICATE_SAME_ACCESS);
\r
9791 return GetLastError();
\r
9793 CloseHandle(hChildStdinWr);
\r
9795 /* Arrange to (1) look in dir for the child .exe file, and
\r
9796 * (2) have dir be the child's working directory. Interpret
\r
9797 * dir relative to the directory WinBoard loaded from. */
\r
9798 GetCurrentDirectory(MSG_SIZ, buf);
\r
9799 SetCurrentDirectory(installDir);
\r
9800 SetCurrentDirectory(dir);
\r
9802 /* Now create the child process. */
\r
9804 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9805 siStartInfo.lpReserved = NULL;
\r
9806 siStartInfo.lpDesktop = NULL;
\r
9807 siStartInfo.lpTitle = NULL;
\r
9808 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9809 siStartInfo.cbReserved2 = 0;
\r
9810 siStartInfo.lpReserved2 = NULL;
\r
9811 siStartInfo.hStdInput = hChildStdinRd;
\r
9812 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9813 siStartInfo.hStdError = hChildStdoutWr;
\r
9815 fSuccess = CreateProcess(NULL,
\r
9816 cmdLine, /* command line */
\r
9817 NULL, /* process security attributes */
\r
9818 NULL, /* primary thread security attrs */
\r
9819 TRUE, /* handles are inherited */
\r
9820 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9821 NULL, /* use parent's environment */
\r
9823 &siStartInfo, /* STARTUPINFO pointer */
\r
9824 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9826 err = GetLastError();
\r
9827 SetCurrentDirectory(buf); /* return to prev directory */
\r
9832 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9833 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9834 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9837 /* Close the handles we don't need in the parent */
\r
9838 CloseHandle(piProcInfo.hThread);
\r
9839 CloseHandle(hChildStdinRd);
\r
9840 CloseHandle(hChildStdoutWr);
\r
9842 /* Prepare return value */
\r
9843 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9844 cp->kind = CPReal;
\r
9845 cp->hProcess = piProcInfo.hProcess;
\r
9846 cp->pid = piProcInfo.dwProcessId;
\r
9847 cp->hFrom = hChildStdoutRdDup;
\r
9848 cp->hTo = hChildStdinWrDup;
\r
9850 *pr = (void *) cp;
\r
9852 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9853 2000 where engines sometimes don't see the initial command(s)
\r
9854 from WinBoard and hang. I don't understand how that can happen,
\r
9855 but the Sleep is harmless, so I've put it in. Others have also
\r
9856 reported what may be the same problem, so hopefully this will fix
\r
9857 it for them too. */
\r
9865 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9867 ChildProc *cp; int result;
\r
9869 cp = (ChildProc *) pr;
\r
9870 if (cp == NULL) return;
\r
9872 switch (cp->kind) {
\r
9874 /* TerminateProcess is considered harmful, so... */
\r
9875 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9876 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9877 /* The following doesn't work because the chess program
\r
9878 doesn't "have the same console" as WinBoard. Maybe
\r
9879 we could arrange for this even though neither WinBoard
\r
9880 nor the chess program uses a console for stdio? */
\r
9881 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9883 /* [AS] Special termination modes for misbehaving programs... */
\r
9884 if( signal == 9 ) {
\r
9885 result = TerminateProcess( cp->hProcess, 0 );
\r
9887 if ( appData.debugMode) {
\r
9888 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9891 else if( signal == 10 ) {
\r
9892 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9894 if( dw != WAIT_OBJECT_0 ) {
\r
9895 result = TerminateProcess( cp->hProcess, 0 );
\r
9897 if ( appData.debugMode) {
\r
9898 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9904 CloseHandle(cp->hProcess);
\r
9908 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9912 closesocket(cp->sock);
\r
9917 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9918 closesocket(cp->sock);
\r
9919 closesocket(cp->sock2);
\r
9927 InterruptChildProcess(ProcRef pr)
\r
9931 cp = (ChildProc *) pr;
\r
9932 if (cp == NULL) return;
\r
9933 switch (cp->kind) {
\r
9935 /* The following doesn't work because the chess program
\r
9936 doesn't "have the same console" as WinBoard. Maybe
\r
9937 we could arrange for this even though neither WinBoard
\r
9938 nor the chess program uses a console for stdio */
\r
9939 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9944 /* Can't interrupt */
\r
9948 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9955 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9957 char cmdLine[MSG_SIZ];
\r
9959 if (port[0] == NULLCHAR) {
\r
9960 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9962 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9964 return StartChildProcess(cmdLine, "", pr);
\r
9968 /* Code to open TCP sockets */
\r
9971 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9976 struct sockaddr_in sa, mysa;
\r
9977 struct hostent FAR *hp;
\r
9978 unsigned short uport;
\r
9979 WORD wVersionRequested;
\r
9982 /* Initialize socket DLL */
\r
9983 wVersionRequested = MAKEWORD(1, 1);
\r
9984 err = WSAStartup(wVersionRequested, &wsaData);
\r
9985 if (err != 0) return err;
\r
9988 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9989 err = WSAGetLastError();
\r
9994 /* Bind local address using (mostly) don't-care values.
\r
9996 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9997 mysa.sin_family = AF_INET;
\r
9998 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9999 uport = (unsigned short) 0;
\r
10000 mysa.sin_port = htons(uport);
\r
10001 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10002 == SOCKET_ERROR) {
\r
10003 err = WSAGetLastError();
\r
10008 /* Resolve remote host name */
\r
10009 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10010 if (!(hp = gethostbyname(host))) {
\r
10011 unsigned int b0, b1, b2, b3;
\r
10013 err = WSAGetLastError();
\r
10015 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10016 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10017 hp->h_addrtype = AF_INET;
\r
10018 hp->h_length = 4;
\r
10019 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10020 hp->h_addr_list[0] = (char *) malloc(4);
\r
10021 hp->h_addr_list[0][0] = (char) b0;
\r
10022 hp->h_addr_list[0][1] = (char) b1;
\r
10023 hp->h_addr_list[0][2] = (char) b2;
\r
10024 hp->h_addr_list[0][3] = (char) b3;
\r
10030 sa.sin_family = hp->h_addrtype;
\r
10031 uport = (unsigned short) atoi(port);
\r
10032 sa.sin_port = htons(uport);
\r
10033 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10035 /* Make connection */
\r
10036 if (connect(s, (struct sockaddr *) &sa,
\r
10037 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10038 err = WSAGetLastError();
\r
10043 /* Prepare return value */
\r
10044 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10045 cp->kind = CPSock;
\r
10047 *pr = (ProcRef *) cp;
\r
10053 OpenCommPort(char *name, ProcRef *pr)
\r
10058 char fullname[MSG_SIZ];
\r
10060 if (*name != '\\')
\r
10061 sprintf(fullname, "\\\\.\\%s", name);
\r
10063 strcpy(fullname, name);
\r
10065 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10066 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10067 if (h == (HANDLE) -1) {
\r
10068 return GetLastError();
\r
10072 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10074 /* Accumulate characters until a 100ms pause, then parse */
\r
10075 ct.ReadIntervalTimeout = 100;
\r
10076 ct.ReadTotalTimeoutMultiplier = 0;
\r
10077 ct.ReadTotalTimeoutConstant = 0;
\r
10078 ct.WriteTotalTimeoutMultiplier = 0;
\r
10079 ct.WriteTotalTimeoutConstant = 0;
\r
10080 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10082 /* Prepare return value */
\r
10083 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10084 cp->kind = CPComm;
\r
10087 *pr = (ProcRef *) cp;
\r
10093 OpenLoopback(ProcRef *pr)
\r
10095 DisplayFatalError("Not implemented", 0, 1);
\r
10101 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10105 SOCKET s, s2, s3;
\r
10106 struct sockaddr_in sa, mysa;
\r
10107 struct hostent FAR *hp;
\r
10108 unsigned short uport;
\r
10109 WORD wVersionRequested;
\r
10112 char stderrPortStr[MSG_SIZ];
\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 /* Resolve remote host name */
\r
10120 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10121 if (!(hp = gethostbyname(host))) {
\r
10122 unsigned int b0, b1, b2, b3;
\r
10124 err = WSAGetLastError();
\r
10126 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10127 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10128 hp->h_addrtype = AF_INET;
\r
10129 hp->h_length = 4;
\r
10130 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10131 hp->h_addr_list[0] = (char *) malloc(4);
\r
10132 hp->h_addr_list[0][0] = (char) b0;
\r
10133 hp->h_addr_list[0][1] = (char) b1;
\r
10134 hp->h_addr_list[0][2] = (char) b2;
\r
10135 hp->h_addr_list[0][3] = (char) b3;
\r
10141 sa.sin_family = hp->h_addrtype;
\r
10142 uport = (unsigned short) 514;
\r
10143 sa.sin_port = htons(uport);
\r
10144 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10146 /* Bind local socket to unused "privileged" port address
\r
10148 s = INVALID_SOCKET;
\r
10149 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10150 mysa.sin_family = AF_INET;
\r
10151 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10152 for (fromPort = 1023;; fromPort--) {
\r
10153 if (fromPort < 0) {
\r
10155 return WSAEADDRINUSE;
\r
10157 if (s == INVALID_SOCKET) {
\r
10158 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10159 err = WSAGetLastError();
\r
10164 uport = (unsigned short) fromPort;
\r
10165 mysa.sin_port = htons(uport);
\r
10166 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10167 == SOCKET_ERROR) {
\r
10168 err = WSAGetLastError();
\r
10169 if (err == WSAEADDRINUSE) continue;
\r
10173 if (connect(s, (struct sockaddr *) &sa,
\r
10174 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10175 err = WSAGetLastError();
\r
10176 if (err == WSAEADDRINUSE) {
\r
10187 /* Bind stderr local socket to unused "privileged" port address
\r
10189 s2 = INVALID_SOCKET;
\r
10190 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10191 mysa.sin_family = AF_INET;
\r
10192 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10193 for (fromPort = 1023;; fromPort--) {
\r
10194 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10195 if (fromPort < 0) {
\r
10196 (void) closesocket(s);
\r
10198 return WSAEADDRINUSE;
\r
10200 if (s2 == INVALID_SOCKET) {
\r
10201 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10202 err = WSAGetLastError();
\r
10208 uport = (unsigned short) fromPort;
\r
10209 mysa.sin_port = htons(uport);
\r
10210 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10211 == SOCKET_ERROR) {
\r
10212 err = WSAGetLastError();
\r
10213 if (err == WSAEADDRINUSE) continue;
\r
10214 (void) closesocket(s);
\r
10218 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10219 err = WSAGetLastError();
\r
10220 if (err == WSAEADDRINUSE) {
\r
10222 s2 = INVALID_SOCKET;
\r
10225 (void) closesocket(s);
\r
10226 (void) closesocket(s2);
\r
10232 prevStderrPort = fromPort; // remember port used
\r
10233 sprintf(stderrPortStr, "%d", fromPort);
\r
10235 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10236 err = WSAGetLastError();
\r
10237 (void) closesocket(s);
\r
10238 (void) closesocket(s2);
\r
10243 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10244 err = WSAGetLastError();
\r
10245 (void) closesocket(s);
\r
10246 (void) closesocket(s2);
\r
10250 if (*user == NULLCHAR) user = UserName();
\r
10251 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10252 err = WSAGetLastError();
\r
10253 (void) closesocket(s);
\r
10254 (void) closesocket(s2);
\r
10258 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10259 err = WSAGetLastError();
\r
10260 (void) closesocket(s);
\r
10261 (void) closesocket(s2);
\r
10266 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10267 err = WSAGetLastError();
\r
10268 (void) closesocket(s);
\r
10269 (void) closesocket(s2);
\r
10273 (void) closesocket(s2); /* Stop listening */
\r
10275 /* Prepare return value */
\r
10276 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10277 cp->kind = CPRcmd;
\r
10280 *pr = (ProcRef *) cp;
\r
10287 AddInputSource(ProcRef pr, int lineByLine,
\r
10288 InputCallback func, VOIDSTAR closure)
\r
10290 InputSource *is, *is2 = NULL;
\r
10291 ChildProc *cp = (ChildProc *) pr;
\r
10293 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10294 is->lineByLine = lineByLine;
\r
10296 is->closure = closure;
\r
10297 is->second = NULL;
\r
10298 is->next = is->buf;
\r
10299 if (pr == NoProc) {
\r
10300 is->kind = CPReal;
\r
10301 consoleInputSource = is;
\r
10303 is->kind = cp->kind;
\r
10305 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10306 we create all threads suspended so that the is->hThread variable can be
\r
10307 safely assigned, then let the threads start with ResumeThread.
\r
10309 switch (cp->kind) {
\r
10311 is->hFile = cp->hFrom;
\r
10312 cp->hFrom = NULL; /* now owned by InputThread */
\r
10314 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10315 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10319 is->hFile = cp->hFrom;
\r
10320 cp->hFrom = NULL; /* now owned by InputThread */
\r
10322 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10323 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10327 is->sock = cp->sock;
\r
10329 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10330 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10334 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10336 is->sock = cp->sock;
\r
10337 is->second = is2;
\r
10338 is2->sock = cp->sock2;
\r
10339 is2->second = is2;
\r
10341 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10342 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10344 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10345 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10349 if( is->hThread != NULL ) {
\r
10350 ResumeThread( is->hThread );
\r
10353 if( is2 != NULL && is2->hThread != NULL ) {
\r
10354 ResumeThread( is2->hThread );
\r
10358 return (InputSourceRef) is;
\r
10362 RemoveInputSource(InputSourceRef isr)
\r
10366 is = (InputSource *) isr;
\r
10367 is->hThread = NULL; /* tell thread to stop */
\r
10368 CloseHandle(is->hThread);
\r
10369 if (is->second != NULL) {
\r
10370 is->second->hThread = NULL;
\r
10371 CloseHandle(is->second->hThread);
\r
10375 int no_wrap(char *message, int count)
\r
10377 ConsoleOutput(message, count, FALSE);
\r
10382 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10385 int outCount = SOCKET_ERROR;
\r
10386 ChildProc *cp = (ChildProc *) pr;
\r
10387 static OVERLAPPED ovl;
\r
10388 static int line = 0;
\r
10390 if (pr == NoProc)
\r
10392 if (appData.noJoin || !appData.useInternalWrap)
\r
10393 return no_wrap(message, count);
\r
10396 int width = get_term_width();
\r
10397 int len = wrap(NULL, message, count, width, &line);
\r
10398 char *msg = malloc(len);
\r
10402 return no_wrap(message, count);
\r
10405 dbgchk = wrap(msg, message, count, width, &line);
\r
10406 if (dbgchk != len && appData.debugMode)
\r
10407 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10408 ConsoleOutput(msg, len, FALSE);
\r
10415 if (ovl.hEvent == NULL) {
\r
10416 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10418 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10420 switch (cp->kind) {
\r
10423 outCount = send(cp->sock, message, count, 0);
\r
10424 if (outCount == SOCKET_ERROR) {
\r
10425 *outError = WSAGetLastError();
\r
10427 *outError = NO_ERROR;
\r
10432 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10433 &dOutCount, NULL)) {
\r
10434 *outError = NO_ERROR;
\r
10435 outCount = (int) dOutCount;
\r
10437 *outError = GetLastError();
\r
10442 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10443 &dOutCount, &ovl);
\r
10444 if (*outError == NO_ERROR) {
\r
10445 outCount = (int) dOutCount;
\r
10453 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10456 /* Ignore delay, not implemented for WinBoard */
\r
10457 return OutputToProcess(pr, message, count, outError);
\r
10462 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10463 char *buf, int count, int error)
\r
10465 DisplayFatalError("Not implemented", 0, 1);
\r
10468 /* see wgamelist.c for Game List functions */
\r
10469 /* see wedittags.c for Edit Tags functions */
\r
10476 char buf[MSG_SIZ];
\r
10479 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10480 f = fopen(buf, "r");
\r
10482 ProcessICSInitScript(f);
\r
10490 StartAnalysisClock()
\r
10492 if (analysisTimerEvent) return;
\r
10493 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10494 (UINT) 2000, NULL);
\r
10498 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10500 static HANDLE hwndText;
\r
10502 static int sizeX, sizeY;
\r
10503 int newSizeX, newSizeY, flags;
\r
10506 switch (message) {
\r
10507 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10508 /* Initialize the dialog items */
\r
10509 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10510 SetWindowText(hDlg, analysisTitle);
\r
10511 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10512 /* Size and position the dialog */
\r
10513 if (!analysisDialog) {
\r
10514 analysisDialog = hDlg;
\r
10515 flags = SWP_NOZORDER;
\r
10516 GetClientRect(hDlg, &rect);
\r
10517 sizeX = rect.right;
\r
10518 sizeY = rect.bottom;
\r
10519 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10520 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10521 WINDOWPLACEMENT wp;
\r
10522 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10523 wp.length = sizeof(WINDOWPLACEMENT);
\r
10525 wp.showCmd = SW_SHOW;
\r
10526 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10527 wp.rcNormalPosition.left = analysisX;
\r
10528 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10529 wp.rcNormalPosition.top = analysisY;
\r
10530 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10531 SetWindowPlacement(hDlg, &wp);
\r
10533 GetClientRect(hDlg, &rect);
\r
10534 newSizeX = rect.right;
\r
10535 newSizeY = rect.bottom;
\r
10536 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10537 newSizeX, newSizeY);
\r
10538 sizeX = newSizeX;
\r
10539 sizeY = newSizeY;
\r
10544 case WM_COMMAND: /* message: received a command */
\r
10545 switch (LOWORD(wParam)) {
\r
10547 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10548 ExitAnalyzeMode();
\r
10560 newSizeX = LOWORD(lParam);
\r
10561 newSizeY = HIWORD(lParam);
\r
10562 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10563 sizeX = newSizeX;
\r
10564 sizeY = newSizeY;
\r
10567 case WM_GETMINMAXINFO:
\r
10568 /* Prevent resizing window too small */
\r
10569 mmi = (MINMAXINFO *) lParam;
\r
10570 mmi->ptMinTrackSize.x = 100;
\r
10571 mmi->ptMinTrackSize.y = 100;
\r
10578 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10580 highlightInfo.sq[0].x = fromX;
\r
10581 highlightInfo.sq[0].y = fromY;
\r
10582 highlightInfo.sq[1].x = toX;
\r
10583 highlightInfo.sq[1].y = toY;
\r
10587 ClearHighlights()
\r
10589 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10590 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10594 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10596 premoveHighlightInfo.sq[0].x = fromX;
\r
10597 premoveHighlightInfo.sq[0].y = fromY;
\r
10598 premoveHighlightInfo.sq[1].x = toX;
\r
10599 premoveHighlightInfo.sq[1].y = toY;
\r
10603 ClearPremoveHighlights()
\r
10605 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10606 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10610 ShutDownFrontEnd()
\r
10612 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10613 DeleteClipboardTempFiles();
\r
10619 if (IsIconic(hwndMain))
\r
10620 ShowWindow(hwndMain, SW_RESTORE);
\r
10622 SetActiveWindow(hwndMain);
\r
10626 * Prototypes for animation support routines
\r
10628 static void ScreenSquare(int column, int row, POINT * pt);
\r
10629 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10630 POINT frames[], int * nFrames);
\r
10634 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10635 { // [HGM] atomic: animate blast wave
\r
10637 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10638 explodeInfo.fromX = fromX;
\r
10639 explodeInfo.fromY = fromY;
\r
10640 explodeInfo.toX = toX;
\r
10641 explodeInfo.toY = toY;
\r
10642 for(i=1; i<nFrames; i++) {
\r
10643 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10644 DrawPosition(FALSE, NULL);
\r
10645 Sleep(appData.animSpeed);
\r
10647 explodeInfo.radius = 0;
\r
10648 DrawPosition(TRUE, NULL);
\r
10651 #define kFactor 4
\r
10654 AnimateMove(board, fromX, fromY, toX, toY)
\r
10661 ChessSquare piece;
\r
10662 POINT start, finish, mid;
\r
10663 POINT frames[kFactor * 2 + 1];
\r
10666 if (!appData.animate) return;
\r
10667 if (doingSizing) return;
\r
10668 if (fromY < 0 || fromX < 0) return;
\r
10669 piece = board[fromY][fromX];
\r
10670 if (piece >= EmptySquare) return;
\r
10672 ScreenSquare(fromX, fromY, &start);
\r
10673 ScreenSquare(toX, toY, &finish);
\r
10675 /* All pieces except knights move in straight line */
\r
10676 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10677 mid.x = start.x + (finish.x - start.x) / 2;
\r
10678 mid.y = start.y + (finish.y - start.y) / 2;
\r
10680 /* Knight: make diagonal movement then straight */
\r
10681 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10682 mid.x = start.x + (finish.x - start.x) / 2;
\r
10683 mid.y = finish.y;
\r
10685 mid.x = finish.x;
\r
10686 mid.y = start.y + (finish.y - start.y) / 2;
\r
10690 /* Don't use as many frames for very short moves */
\r
10691 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10692 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10694 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10696 animInfo.from.x = fromX;
\r
10697 animInfo.from.y = fromY;
\r
10698 animInfo.to.x = toX;
\r
10699 animInfo.to.y = toY;
\r
10700 animInfo.lastpos = start;
\r
10701 animInfo.piece = piece;
\r
10702 for (n = 0; n < nFrames; n++) {
\r
10703 animInfo.pos = frames[n];
\r
10704 DrawPosition(FALSE, NULL);
\r
10705 animInfo.lastpos = animInfo.pos;
\r
10706 Sleep(appData.animSpeed);
\r
10708 animInfo.pos = finish;
\r
10709 DrawPosition(FALSE, NULL);
\r
10710 animInfo.piece = EmptySquare;
\r
10711 if(gameInfo.variant == VariantAtomic &&
\r
10712 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10713 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10716 /* Convert board position to corner of screen rect and color */
\r
10719 ScreenSquare(column, row, pt)
\r
10720 int column; int row; POINT * pt;
\r
10723 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10724 pt->y = lineGap + row * (squareSize + lineGap);
\r
10726 pt->x = lineGap + column * (squareSize + lineGap);
\r
10727 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10731 /* Generate a series of frame coords from start->mid->finish.
\r
10732 The movement rate doubles until the half way point is
\r
10733 reached, then halves back down to the final destination,
\r
10734 which gives a nice slow in/out effect. The algorithmn
\r
10735 may seem to generate too many intermediates for short
\r
10736 moves, but remember that the purpose is to attract the
\r
10737 viewers attention to the piece about to be moved and
\r
10738 then to where it ends up. Too few frames would be less
\r
10742 Tween(start, mid, finish, factor, frames, nFrames)
\r
10743 POINT * start; POINT * mid;
\r
10744 POINT * finish; int factor;
\r
10745 POINT frames[]; int * nFrames;
\r
10747 int n, fraction = 1, count = 0;
\r
10749 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10750 for (n = 0; n < factor; n++)
\r
10752 for (n = 0; n < factor; n++) {
\r
10753 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10754 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10756 fraction = fraction / 2;
\r
10760 frames[count] = *mid;
\r
10763 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10765 for (n = 0; n < factor; n++) {
\r
10766 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10767 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10769 fraction = fraction * 2;
\r
10771 *nFrames = count;
\r
10775 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10777 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10779 EvalGraphSet( first, last, current, pvInfoList );
\r
10782 void SetProgramStats( FrontEndProgramStats * stats )
\r
10784 EngineOutputUpdate( stats );
\r