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
1465 /* Command line font name parser. NULL name means do nothing.
\r
1466 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1467 For backward compatibility, syntax without the colon is also
\r
1468 accepted, but font names with digits in them won't work in that case.
\r
1471 ParseFontName(char *name, MyFontParams *mfp)
\r
1474 if (name == NULL) return;
\r
1476 q = strchr(p, ':');
\r
1478 if (q - p >= sizeof(mfp->faceName))
\r
1479 ExitArgError("Font name too long:", name);
\r
1480 memcpy(mfp->faceName, p, q - p);
\r
1481 mfp->faceName[q - p] = NULLCHAR;
\r
1484 q = mfp->faceName;
\r
1485 while (*p && !isdigit(*p)) {
\r
1487 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1488 ExitArgError("Font name too long:", name);
\r
1490 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1493 if (!*p) ExitArgError("Font point size missing:", name);
\r
1494 mfp->pointSize = (float) atof(p);
\r
1495 mfp->bold = (strchr(p, 'b') != NULL);
\r
1496 mfp->italic = (strchr(p, 'i') != NULL);
\r
1497 mfp->underline = (strchr(p, 'u') != NULL);
\r
1498 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1499 mfp->charset = DEFAULT_CHARSET;
\r
1500 q = strchr(p, 'c');
\r
1502 mfp->charset = (BYTE) atoi(q+1);
\r
1505 /* Color name parser.
\r
1506 X version accepts X color names, but this one
\r
1507 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1509 ParseColorName(char *name)
\r
1511 int red, green, blue, count;
\r
1512 char buf[MSG_SIZ];
\r
1514 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1516 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1517 &red, &green, &blue);
\r
1520 sprintf(buf, "Can't parse color name %s", name);
\r
1521 DisplayError(buf, 0);
\r
1522 return RGB(0, 0, 0);
\r
1524 return PALETTERGB(red, green, blue);
\r
1528 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1530 char *e = argValue;
\r
1534 if (*e == 'b') eff |= CFE_BOLD;
\r
1535 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1536 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1537 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1538 else if (*e == '#' || isdigit(*e)) break;
\r
1542 *color = ParseColorName(e);
\r
1547 ParseBoardSize(char *name)
\r
1549 BoardSize bs = SizeTiny;
\r
1550 while (sizeInfo[bs].name != NULL) {
\r
1551 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1554 ExitArgError("Unrecognized board size value", name);
\r
1555 return bs; /* not reached */
\r
1560 StringGet(void *getClosure)
\r
1562 char **p = (char **) getClosure;
\r
1567 FileGet(void *getClosure)
\r
1570 FILE* f = (FILE*) getClosure;
\r
1573 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1580 /* Parse settings file named "name". If file found, return the
\r
1581 full name in fullname and return TRUE; else return FALSE */
\r
1583 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1587 int ok; char buf[MSG_SIZ];
\r
1589 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1590 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1591 sprintf(buf, "%s.ini", name);
\r
1592 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1595 f = fopen(fullname, "r");
\r
1597 ParseArgs(FileGet, f);
\r
1606 ParseArgs(GetFunc get, void *cl)
\r
1608 char argName[ARG_MAX];
\r
1609 char argValue[ARG_MAX];
\r
1610 ArgDescriptor *ad;
\r
1619 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1620 if (ch == NULLCHAR) break;
\r
1622 /* Comment to end of line */
\r
1624 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1626 } else if (ch == '/' || ch == '-') {
\r
1629 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1630 ch != '\n' && ch != '\t') {
\r
1636 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1637 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1639 if (ad->argName == NULL)
\r
1640 ExitArgError("Unrecognized argument", argName);
\r
1642 } else if (ch == '@') {
\r
1643 /* Indirection file */
\r
1644 ad = &argDescriptorIndirection;
\r
1647 /* Positional argument */
\r
1648 ad = &argDescriptors[posarg++];
\r
1649 strcpy(argName, ad->argName);
\r
1652 if (ad->argType == ArgTrue) {
\r
1653 *(Boolean *) ad->argLoc = TRUE;
\r
1656 if (ad->argType == ArgFalse) {
\r
1657 *(Boolean *) ad->argLoc = FALSE;
\r
1661 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1662 if (ch == NULLCHAR || ch == '\n') {
\r
1663 ExitArgError("No value provided for argument", argName);
\r
1667 // Quoting with { }. No characters have to (or can) be escaped.
\r
1668 // Thus the string cannot contain a '}' character.
\r
1688 } else if (ch == '\'' || ch == '"') {
\r
1689 // Quoting with ' ' or " ", with \ as escape character.
\r
1690 // Inconvenient for long strings that may contain Windows filenames.
\r
1707 if (ch == start) {
\r
1716 if (ad->argType == ArgFilename
\r
1717 || ad->argType == ArgSettingsFilename) {
\r
1723 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1747 for (i = 0; i < 3; i++) {
\r
1748 if (ch >= '0' && ch <= '7') {
\r
1749 octval = octval*8 + (ch - '0');
\r
1756 *q++ = (char) octval;
\r
1767 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1774 switch (ad->argType) {
\r
1776 *(int *) ad->argLoc = atoi(argValue);
\r
1780 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1784 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1788 *(int *) ad->argLoc = atoi(argValue);
\r
1789 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1793 *(float *) ad->argLoc = (float) atof(argValue);
\r
1798 *(char **) ad->argLoc = strdup(argValue);
\r
1801 case ArgSettingsFilename:
\r
1803 char fullname[MSG_SIZ];
\r
1804 if (ParseSettingsFile(argValue, fullname)) {
\r
1805 if (ad->argLoc != NULL) {
\r
1806 *(char **) ad->argLoc = strdup(fullname);
\r
1809 if (ad->argLoc != NULL) {
\r
1811 ExitArgError("Failed to open indirection file", argValue);
\r
1818 switch (argValue[0]) {
\r
1821 *(Boolean *) ad->argLoc = TRUE;
\r
1825 *(Boolean *) ad->argLoc = FALSE;
\r
1828 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1834 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1837 case ArgAttribs: {
\r
1838 ColorClass cc = (ColorClass)ad->argLoc;
\r
1839 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1843 case ArgBoardSize:
\r
1844 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1848 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1851 case ArgCommSettings:
\r
1852 ParseCommSettings(argValue, &dcb);
\r
1856 ExitArgError("Unrecognized argument", argValue);
\r
1865 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1867 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1868 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1871 lf->lfEscapement = 0;
\r
1872 lf->lfOrientation = 0;
\r
1873 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1874 lf->lfItalic = mfp->italic;
\r
1875 lf->lfUnderline = mfp->underline;
\r
1876 lf->lfStrikeOut = mfp->strikeout;
\r
1877 lf->lfCharSet = mfp->charset;
\r
1878 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1879 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1880 lf->lfQuality = DEFAULT_QUALITY;
\r
1881 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1882 strcpy(lf->lfFaceName, mfp->faceName);
\r
1886 CreateFontInMF(MyFont *mf)
\r
1888 LFfromMFP(&mf->lf, &mf->mfp);
\r
1889 if (mf->hf) DeleteObject(mf->hf);
\r
1890 mf->hf = CreateFontIndirect(&mf->lf);
\r
1894 SetDefaultTextAttribs()
\r
1897 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1898 ParseAttribs(&textAttribs[cc].color,
\r
1899 &textAttribs[cc].effects,
\r
1900 defaultTextAttribs[cc]);
\r
1905 SetDefaultSounds()
\r
1909 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1910 textAttribs[cc].sound.name = strdup("");
\r
1911 textAttribs[cc].sound.data = NULL;
\r
1913 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1914 sounds[sc].name = strdup("");
\r
1915 sounds[sc].data = NULL;
\r
1917 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1925 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1926 MyLoadSound(&textAttribs[cc].sound);
\r
1928 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1929 MyLoadSound(&sounds[sc]);
\r
1934 InitAppData(LPSTR lpCmdLine)
\r
1937 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1940 programName = szAppName;
\r
1942 /* Initialize to defaults */
\r
1943 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1944 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1945 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1946 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1947 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1948 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1949 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1950 SetDefaultTextAttribs();
\r
1951 SetDefaultSounds();
\r
1952 appData.movesPerSession = MOVES_PER_SESSION;
\r
1953 appData.initString = INIT_STRING;
\r
1954 appData.secondInitString = INIT_STRING;
\r
1955 appData.firstComputerString = COMPUTER_STRING;
\r
1956 appData.secondComputerString = COMPUTER_STRING;
\r
1957 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1958 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1959 appData.firstPlaysBlack = FALSE;
\r
1960 appData.noChessProgram = FALSE;
\r
1961 chessProgram = FALSE;
\r
1962 appData.firstHost = FIRST_HOST;
\r
1963 appData.secondHost = SECOND_HOST;
\r
1964 appData.firstDirectory = FIRST_DIRECTORY;
\r
1965 appData.secondDirectory = SECOND_DIRECTORY;
\r
1966 appData.bitmapDirectory = "";
\r
1967 appData.remoteShell = REMOTE_SHELL;
\r
1968 appData.remoteUser = "";
\r
1969 appData.timeDelay = TIME_DELAY;
\r
1970 appData.timeControl = TIME_CONTROL;
\r
1971 appData.timeIncrement = TIME_INCREMENT;
\r
1972 appData.icsActive = FALSE;
\r
1973 appData.icsHost = "";
\r
1974 appData.icsPort = ICS_PORT;
\r
1975 appData.icsCommPort = ICS_COMM_PORT;
\r
1976 appData.icsLogon = ICS_LOGON;
\r
1977 appData.icsHelper = "";
\r
1978 appData.useTelnet = FALSE;
\r
1979 appData.telnetProgram = TELNET_PROGRAM;
\r
1980 appData.gateway = "";
\r
1981 appData.loadGameFile = "";
\r
1982 appData.loadGameIndex = 0;
\r
1983 appData.saveGameFile = "";
\r
1984 appData.autoSaveGames = FALSE;
\r
1985 appData.loadPositionFile = "";
\r
1986 appData.loadPositionIndex = 1;
\r
1987 appData.savePositionFile = "";
\r
1988 appData.matchMode = FALSE;
\r
1989 appData.matchGames = 0;
\r
1990 appData.monoMode = FALSE;
\r
1991 appData.debugMode = FALSE;
\r
1992 appData.clockMode = TRUE;
\r
1993 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1994 appData.Iconic = FALSE; /*unused*/
\r
1995 appData.searchTime = "";
\r
1996 appData.searchDepth = 0;
\r
1997 appData.showCoords = FALSE;
\r
1998 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1999 appData.autoCallFlag = FALSE;
\r
2000 appData.flipView = FALSE;
\r
2001 appData.autoFlipView = TRUE;
\r
2002 appData.cmailGameName = "";
\r
2003 appData.alwaysPromoteToQueen = FALSE;
\r
2004 appData.oldSaveStyle = FALSE;
\r
2005 appData.quietPlay = FALSE;
\r
2006 appData.showThinking = FALSE;
\r
2007 appData.ponderNextMove = TRUE;
\r
2008 appData.periodicUpdates = TRUE;
\r
2009 appData.popupExitMessage = TRUE;
\r
2010 appData.popupMoveErrors = FALSE;
\r
2011 appData.autoObserve = FALSE;
\r
2012 appData.autoComment = FALSE;
\r
2013 appData.animate = TRUE;
\r
2014 appData.animSpeed = 10;
\r
2015 appData.animateDragging = TRUE;
\r
2016 appData.highlightLastMove = TRUE;
\r
2017 appData.getMoveList = TRUE;
\r
2018 appData.testLegality = TRUE;
\r
2019 appData.premove = TRUE;
\r
2020 appData.premoveWhite = FALSE;
\r
2021 appData.premoveWhiteText = "";
\r
2022 appData.premoveBlack = FALSE;
\r
2023 appData.premoveBlackText = "";
\r
2024 appData.icsAlarm = TRUE;
\r
2025 appData.icsAlarmTime = 5000;
\r
2026 appData.autoRaiseBoard = TRUE;
\r
2027 appData.localLineEditing = TRUE;
\r
2028 appData.colorize = TRUE;
\r
2029 appData.reuseFirst = TRUE;
\r
2030 appData.reuseSecond = TRUE;
\r
2031 appData.blindfold = FALSE;
\r
2032 appData.icsEngineAnalyze = FALSE;
\r
2033 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2034 dcb.DCBlength = sizeof(DCB);
\r
2035 dcb.BaudRate = 9600;
\r
2036 dcb.fBinary = TRUE;
\r
2037 dcb.fParity = FALSE;
\r
2038 dcb.fOutxCtsFlow = FALSE;
\r
2039 dcb.fOutxDsrFlow = FALSE;
\r
2040 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2041 dcb.fDsrSensitivity = FALSE;
\r
2042 dcb.fTXContinueOnXoff = TRUE;
\r
2043 dcb.fOutX = FALSE;
\r
2045 dcb.fNull = FALSE;
\r
2046 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2047 dcb.fAbortOnError = FALSE;
\r
2049 dcb.Parity = SPACEPARITY;
\r
2050 dcb.StopBits = ONESTOPBIT;
\r
2051 settingsFileName = SETTINGS_FILE;
\r
2052 saveSettingsOnExit = TRUE;
\r
2053 boardX = CW_USEDEFAULT;
\r
2054 boardY = CW_USEDEFAULT;
\r
2055 analysisX = CW_USEDEFAULT;
\r
2056 analysisY = CW_USEDEFAULT;
\r
2057 analysisW = CW_USEDEFAULT;
\r
2058 analysisH = CW_USEDEFAULT;
\r
2059 commentX = CW_USEDEFAULT;
\r
2060 commentY = CW_USEDEFAULT;
\r
2061 commentW = CW_USEDEFAULT;
\r
2062 commentH = CW_USEDEFAULT;
\r
2063 editTagsX = CW_USEDEFAULT;
\r
2064 editTagsY = CW_USEDEFAULT;
\r
2065 editTagsW = CW_USEDEFAULT;
\r
2066 editTagsH = CW_USEDEFAULT;
\r
2067 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2068 icsNames = ICS_NAMES;
\r
2069 firstChessProgramNames = FCP_NAMES;
\r
2070 secondChessProgramNames = SCP_NAMES;
\r
2071 appData.initialMode = "";
\r
2072 appData.variant = "normal";
\r
2073 appData.firstProtocolVersion = PROTOVER;
\r
2074 appData.secondProtocolVersion = PROTOVER;
\r
2075 appData.showButtonBar = TRUE;
\r
2077 /* [AS] New properties (see comments in header file) */
\r
2078 appData.firstScoreIsAbsolute = FALSE;
\r
2079 appData.secondScoreIsAbsolute = FALSE;
\r
2080 appData.saveExtendedInfoInPGN = FALSE;
\r
2081 appData.hideThinkingFromHuman = FALSE;
\r
2082 appData.liteBackTextureFile = "";
\r
2083 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2084 appData.darkBackTextureFile = "";
\r
2085 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2086 appData.renderPiecesWithFont = "";
\r
2087 appData.fontToPieceTable = "";
\r
2088 appData.fontBackColorWhite = 0;
\r
2089 appData.fontForeColorWhite = 0;
\r
2090 appData.fontBackColorBlack = 0;
\r
2091 appData.fontForeColorBlack = 0;
\r
2092 appData.fontPieceSize = 80;
\r
2093 appData.overrideLineGap = 1;
\r
2094 appData.adjudicateLossThreshold = 0;
\r
2095 appData.delayBeforeQuit = 0;
\r
2096 appData.delayAfterQuit = 0;
\r
2097 appData.nameOfDebugFile = "winboard.debug";
\r
2098 appData.pgnEventHeader = "Computer Chess Game";
\r
2099 appData.defaultFrcPosition = -1;
\r
2100 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2101 appData.saveOutOfBookInfo = TRUE;
\r
2102 appData.showEvalInMoveHistory = TRUE;
\r
2103 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2104 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2105 appData.highlightMoveWithArrow = FALSE;
\r
2106 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2107 appData.useStickyWindows = TRUE;
\r
2108 appData.adjudicateDrawMoves = 0;
\r
2109 appData.autoDisplayComment = TRUE;
\r
2110 appData.autoDisplayTags = TRUE;
\r
2111 appData.firstIsUCI = FALSE;
\r
2112 appData.secondIsUCI = FALSE;
\r
2113 appData.firstHasOwnBookUCI = TRUE;
\r
2114 appData.secondHasOwnBookUCI = TRUE;
\r
2115 appData.polyglotDir = "";
\r
2116 appData.usePolyglotBook = FALSE;
\r
2117 appData.polyglotBook = "";
\r
2118 appData.defaultHashSize = 64;
\r
2119 appData.defaultCacheSizeEGTB = 4;
\r
2120 appData.defaultPathEGTB = "c:\\egtb";
\r
2121 appData.firstOptions = "";
\r
2122 appData.secondOptions = "";
\r
2124 InitWindowPlacement( &wpGameList );
\r
2125 InitWindowPlacement( &wpMoveHistory );
\r
2126 InitWindowPlacement( &wpEvalGraph );
\r
2127 InitWindowPlacement( &wpEngineOutput );
\r
2128 InitWindowPlacement( &wpConsole );
\r
2130 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2131 appData.NrFiles = -1;
\r
2132 appData.NrRanks = -1;
\r
2133 appData.holdingsSize = -1;
\r
2134 appData.testClaims = FALSE;
\r
2135 appData.checkMates = FALSE;
\r
2136 appData.materialDraws= FALSE;
\r
2137 appData.trivialDraws = FALSE;
\r
2138 appData.ruleMoves = 51;
\r
2139 appData.drawRepeats = 6;
\r
2140 appData.matchPause = 10000;
\r
2141 appData.alphaRank = FALSE;
\r
2142 appData.allWhite = FALSE;
\r
2143 appData.upsideDown = FALSE;
\r
2144 appData.serverPause = 15;
\r
2145 appData.serverMovesName = NULL;
\r
2146 appData.suppressLoadMoves = FALSE;
\r
2147 appData.firstTimeOdds = 1;
\r
2148 appData.secondTimeOdds = 1;
\r
2149 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2150 appData.secondAccumulateTC = 1;
\r
2151 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2152 appData.secondNPS = -1;
\r
2153 appData.engineComments = 1;
\r
2154 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2155 appData.egtFormats = "";
\r
2158 appData.zippyTalk = ZIPPY_TALK;
\r
2159 appData.zippyPlay = ZIPPY_PLAY;
\r
2160 appData.zippyLines = ZIPPY_LINES;
\r
2161 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2162 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2163 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2164 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2165 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2166 appData.zippyUseI = ZIPPY_USE_I;
\r
2167 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2168 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2169 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2170 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2171 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2172 appData.zippyAbort = ZIPPY_ABORT;
\r
2173 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2174 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2175 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2178 /* Point font array elements to structures and
\r
2179 parse default font names */
\r
2180 for (i=0; i<NUM_FONTS; i++) {
\r
2181 for (j=0; j<NUM_SIZES; j++) {
\r
2182 font[j][i] = &fontRec[j][i];
\r
2183 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2187 /* Parse default settings file if any */
\r
2188 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2189 settingsFileName = strdup(buf);
\r
2192 /* Parse command line */
\r
2193 ParseArgs(StringGet, &lpCmdLine);
\r
2195 /* [HGM] make sure board size is acceptable */
\r
2196 if(appData.NrFiles > BOARD_SIZE ||
\r
2197 appData.NrRanks > BOARD_SIZE )
\r
2198 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2200 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2201 * with options from the command line, we now make an even higher priority
\r
2202 * overrule by WB options attached to the engine command line. This so that
\r
2203 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2206 if(appData.firstChessProgram != NULL) {
\r
2207 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2208 static char *f = "first";
\r
2209 char buf[MSG_SIZ], *q = buf;
\r
2210 if(p != NULL) { // engine command line contains WinBoard options
\r
2211 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2212 ParseArgs(StringGet, &q);
\r
2213 p[-1] = 0; // cut them offengine command line
\r
2216 // now do same for second chess program
\r
2217 if(appData.secondChessProgram != NULL) {
\r
2218 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2219 static char *s = "second";
\r
2220 char buf[MSG_SIZ], *q = buf;
\r
2221 if(p != NULL) { // engine command line contains WinBoard options
\r
2222 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2223 ParseArgs(StringGet, &q);
\r
2224 p[-1] = 0; // cut them offengine command line
\r
2229 /* Propagate options that affect others */
\r
2230 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2231 if (appData.icsActive || appData.noChessProgram) {
\r
2232 chessProgram = FALSE; /* not local chess program mode */
\r
2235 /* Open startup dialog if needed */
\r
2236 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2237 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2238 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2239 *appData.secondChessProgram == NULLCHAR))) {
\r
2242 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2243 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2244 FreeProcInstance(lpProc);
\r
2247 /* Make sure save files land in the right (?) directory */
\r
2248 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2249 appData.saveGameFile = strdup(buf);
\r
2251 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2252 appData.savePositionFile = strdup(buf);
\r
2255 /* Finish initialization for fonts and sounds */
\r
2256 for (i=0; i<NUM_FONTS; i++) {
\r
2257 for (j=0; j<NUM_SIZES; j++) {
\r
2258 CreateFontInMF(font[j][i]);
\r
2261 /* xboard, and older WinBoards, controlled the move sound with the
\r
2262 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2263 always turn the option on (so that the backend will call us),
\r
2264 then let the user turn the sound off by setting it to silence if
\r
2265 desired. To accommodate old winboard.ini files saved by old
\r
2266 versions of WinBoard, we also turn off the sound if the option
\r
2267 was initially set to false. */
\r
2268 if (!appData.ringBellAfterMoves) {
\r
2269 sounds[(int)SoundMove].name = strdup("");
\r
2270 appData.ringBellAfterMoves = TRUE;
\r
2272 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2273 SetCurrentDirectory(installDir);
\r
2275 SetCurrentDirectory(currDir);
\r
2277 p = icsTextMenuString;
\r
2278 if (p[0] == '@') {
\r
2279 FILE* f = fopen(p + 1, "r");
\r
2281 DisplayFatalError(p + 1, errno, 2);
\r
2284 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2286 buf[i] = NULLCHAR;
\r
2289 ParseIcsTextMenu(strdup(p));
\r
2296 HMENU hmenu = GetMenu(hwndMain);
\r
2298 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2299 MF_BYCOMMAND|((appData.icsActive &&
\r
2300 *appData.icsCommPort != NULLCHAR) ?
\r
2301 MF_ENABLED : MF_GRAYED));
\r
2302 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2303 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2304 MF_CHECKED : MF_UNCHECKED));
\r
2309 SaveSettings(char* name)
\r
2312 ArgDescriptor *ad;
\r
2313 WINDOWPLACEMENT wp;
\r
2314 char dir[MSG_SIZ];
\r
2316 if (!hwndMain) return;
\r
2318 GetCurrentDirectory(MSG_SIZ, dir);
\r
2319 SetCurrentDirectory(installDir);
\r
2320 f = fopen(name, "w");
\r
2321 SetCurrentDirectory(dir);
\r
2323 DisplayError(name, errno);
\r
2326 fprintf(f, ";\n");
\r
2327 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2328 fprintf(f, ";\n");
\r
2329 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2330 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2331 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2332 fprintf(f, ";\n");
\r
2334 wp.length = sizeof(WINDOWPLACEMENT);
\r
2335 GetWindowPlacement(hwndMain, &wp);
\r
2336 boardX = wp.rcNormalPosition.left;
\r
2337 boardY = wp.rcNormalPosition.top;
\r
2339 if (hwndConsole) {
\r
2340 GetWindowPlacement(hwndConsole, &wp);
\r
2341 wpConsole.x = wp.rcNormalPosition.left;
\r
2342 wpConsole.y = wp.rcNormalPosition.top;
\r
2343 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (analysisDialog) {
\r
2348 GetWindowPlacement(analysisDialog, &wp);
\r
2349 analysisX = wp.rcNormalPosition.left;
\r
2350 analysisY = wp.rcNormalPosition.top;
\r
2351 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 if (commentDialog) {
\r
2356 GetWindowPlacement(commentDialog, &wp);
\r
2357 commentX = wp.rcNormalPosition.left;
\r
2358 commentY = wp.rcNormalPosition.top;
\r
2359 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2360 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2363 if (editTagsDialog) {
\r
2364 GetWindowPlacement(editTagsDialog, &wp);
\r
2365 editTagsX = wp.rcNormalPosition.left;
\r
2366 editTagsY = wp.rcNormalPosition.top;
\r
2367 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2368 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2371 if (gameListDialog) {
\r
2372 GetWindowPlacement(gameListDialog, &wp);
\r
2373 wpGameList.x = wp.rcNormalPosition.left;
\r
2374 wpGameList.y = wp.rcNormalPosition.top;
\r
2375 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2376 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2379 /* [AS] Move history */
\r
2380 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2382 if( moveHistoryDialog ) {
\r
2383 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2384 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2385 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2386 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2387 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2390 /* [AS] Eval graph */
\r
2391 wpEvalGraph.visible = EvalGraphIsUp();
\r
2393 if( evalGraphDialog ) {
\r
2394 GetWindowPlacement(evalGraphDialog, &wp);
\r
2395 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2396 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2397 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2398 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2401 /* [AS] Engine output */
\r
2402 wpEngineOutput.visible = EngineOutputIsUp();
\r
2404 if( engineOutputDialog ) {
\r
2405 GetWindowPlacement(engineOutputDialog, &wp);
\r
2406 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2407 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2408 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2409 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2412 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2413 if (!ad->save) continue;
\r
2414 switch (ad->argType) {
\r
2417 char *p = *(char **)ad->argLoc;
\r
2418 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2419 /* Quote multiline values or \-containing values
\r
2420 with { } if possible */
\r
2421 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2423 /* Else quote with " " */
\r
2424 fprintf(f, "/%s=\"", ad->argName);
\r
2426 if (*p == '\n') fprintf(f, "\n");
\r
2427 else if (*p == '\r') fprintf(f, "\\r");
\r
2428 else if (*p == '\t') fprintf(f, "\\t");
\r
2429 else if (*p == '\b') fprintf(f, "\\b");
\r
2430 else if (*p == '\f') fprintf(f, "\\f");
\r
2431 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2432 else if (*p == '\"') fprintf(f, "\\\"");
\r
2433 else if (*p == '\\') fprintf(f, "\\\\");
\r
2437 fprintf(f, "\"\n");
\r
2443 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2446 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2449 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2452 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2455 fprintf(f, "/%s=%s\n", ad->argName,
\r
2456 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2459 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2462 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2466 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2467 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2468 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2473 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2474 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2475 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2476 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2477 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2478 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2479 (ta->effects) ? " " : "",
\r
2480 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2484 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2485 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2487 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2490 case ArgBoardSize:
\r
2491 fprintf(f, "/%s=%s\n", ad->argName,
\r
2492 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2497 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2498 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2499 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2500 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2501 ad->argName, mfp->faceName, mfp->pointSize,
\r
2502 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2503 mfp->bold ? "b" : "",
\r
2504 mfp->italic ? "i" : "",
\r
2505 mfp->underline ? "u" : "",
\r
2506 mfp->strikeout ? "s" : "",
\r
2507 (int)mfp->charset);
\r
2511 case ArgCommSettings:
\r
2512 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2514 case ArgSettingsFilename: ;
\r
2522 /*---------------------------------------------------------------------------*\
\r
2524 * GDI board drawing routines
\r
2526 \*---------------------------------------------------------------------------*/
\r
2528 /* [AS] Draw square using background texture */
\r
2529 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2534 return; /* Should never happen! */
\r
2537 SetGraphicsMode( dst, GM_ADVANCED );
\r
2544 /* X reflection */
\r
2549 x.eDx = (FLOAT) dw + dx - 1;
\r
2552 SetWorldTransform( dst, &x );
\r
2555 /* Y reflection */
\r
2561 x.eDy = (FLOAT) dh + dy - 1;
\r
2563 SetWorldTransform( dst, &x );
\r
2571 x.eDx = (FLOAT) dx;
\r
2572 x.eDy = (FLOAT) dy;
\r
2575 SetWorldTransform( dst, &x );
\r
2579 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2587 SetWorldTransform( dst, &x );
\r
2589 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2592 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2594 PM_WP = (int) WhitePawn,
\r
2595 PM_WN = (int) WhiteKnight,
\r
2596 PM_WB = (int) WhiteBishop,
\r
2597 PM_WR = (int) WhiteRook,
\r
2598 PM_WQ = (int) WhiteQueen,
\r
2599 PM_WF = (int) WhiteFerz,
\r
2600 PM_WW = (int) WhiteWazir,
\r
2601 PM_WE = (int) WhiteAlfil,
\r
2602 PM_WM = (int) WhiteMan,
\r
2603 PM_WO = (int) WhiteCannon,
\r
2604 PM_WU = (int) WhiteUnicorn,
\r
2605 PM_WH = (int) WhiteNightrider,
\r
2606 PM_WA = (int) WhiteAngel,
\r
2607 PM_WC = (int) WhiteMarshall,
\r
2608 PM_WAB = (int) WhiteCardinal,
\r
2609 PM_WD = (int) WhiteDragon,
\r
2610 PM_WL = (int) WhiteLance,
\r
2611 PM_WS = (int) WhiteCobra,
\r
2612 PM_WV = (int) WhiteFalcon,
\r
2613 PM_WSG = (int) WhiteSilver,
\r
2614 PM_WG = (int) WhiteGrasshopper,
\r
2615 PM_WK = (int) WhiteKing,
\r
2616 PM_BP = (int) BlackPawn,
\r
2617 PM_BN = (int) BlackKnight,
\r
2618 PM_BB = (int) BlackBishop,
\r
2619 PM_BR = (int) BlackRook,
\r
2620 PM_BQ = (int) BlackQueen,
\r
2621 PM_BF = (int) BlackFerz,
\r
2622 PM_BW = (int) BlackWazir,
\r
2623 PM_BE = (int) BlackAlfil,
\r
2624 PM_BM = (int) BlackMan,
\r
2625 PM_BO = (int) BlackCannon,
\r
2626 PM_BU = (int) BlackUnicorn,
\r
2627 PM_BH = (int) BlackNightrider,
\r
2628 PM_BA = (int) BlackAngel,
\r
2629 PM_BC = (int) BlackMarshall,
\r
2630 PM_BG = (int) BlackGrasshopper,
\r
2631 PM_BAB = (int) BlackCardinal,
\r
2632 PM_BD = (int) BlackDragon,
\r
2633 PM_BL = (int) BlackLance,
\r
2634 PM_BS = (int) BlackCobra,
\r
2635 PM_BV = (int) BlackFalcon,
\r
2636 PM_BSG = (int) BlackSilver,
\r
2637 PM_BK = (int) BlackKing
\r
2640 static HFONT hPieceFont = NULL;
\r
2641 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2642 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2643 static int fontBitmapSquareSize = 0;
\r
2644 static char pieceToFontChar[(int) EmptySquare] =
\r
2645 { 'p', 'n', 'b', 'r', 'q',
\r
2646 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2647 'k', 'o', 'm', 'v', 't', 'w',
\r
2648 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2651 extern BOOL SetCharTable( char *table, const char * map );
\r
2652 /* [HGM] moved to backend.c */
\r
2654 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2657 BYTE r1 = GetRValue( color );
\r
2658 BYTE g1 = GetGValue( color );
\r
2659 BYTE b1 = GetBValue( color );
\r
2665 /* Create a uniform background first */
\r
2666 hbrush = CreateSolidBrush( color );
\r
2667 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2668 FillRect( hdc, &rc, hbrush );
\r
2669 DeleteObject( hbrush );
\r
2672 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2673 int steps = squareSize / 2;
\r
2676 for( i=0; i<steps; i++ ) {
\r
2677 BYTE r = r1 - (r1-r2) * i / steps;
\r
2678 BYTE g = g1 - (g1-g2) * i / steps;
\r
2679 BYTE b = b1 - (b1-b2) * i / steps;
\r
2681 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2682 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2683 FillRect( hdc, &rc, hbrush );
\r
2684 DeleteObject(hbrush);
\r
2687 else if( mode == 2 ) {
\r
2688 /* Diagonal gradient, good more or less for every piece */
\r
2689 POINT triangle[3];
\r
2690 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2691 HBRUSH hbrush_old;
\r
2692 int steps = squareSize;
\r
2695 triangle[0].x = squareSize - steps;
\r
2696 triangle[0].y = squareSize;
\r
2697 triangle[1].x = squareSize;
\r
2698 triangle[1].y = squareSize;
\r
2699 triangle[2].x = squareSize;
\r
2700 triangle[2].y = squareSize - steps;
\r
2702 for( i=0; i<steps; i++ ) {
\r
2703 BYTE r = r1 - (r1-r2) * i / steps;
\r
2704 BYTE g = g1 - (g1-g2) * i / steps;
\r
2705 BYTE b = b1 - (b1-b2) * i / steps;
\r
2707 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2708 hbrush_old = SelectObject( hdc, hbrush );
\r
2709 Polygon( hdc, triangle, 3 );
\r
2710 SelectObject( hdc, hbrush_old );
\r
2711 DeleteObject(hbrush);
\r
2716 SelectObject( hdc, hpen );
\r
2721 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2722 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2723 piece: follow the steps as explained below.
\r
2725 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2729 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2733 int backColor = whitePieceColor;
\r
2734 int foreColor = blackPieceColor;
\r
2736 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2737 backColor = appData.fontBackColorWhite;
\r
2738 foreColor = appData.fontForeColorWhite;
\r
2740 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2741 backColor = appData.fontBackColorBlack;
\r
2742 foreColor = appData.fontForeColorBlack;
\r
2746 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2748 hbm_old = SelectObject( hdc, hbm );
\r
2752 rc.right = squareSize;
\r
2753 rc.bottom = squareSize;
\r
2755 /* Step 1: background is now black */
\r
2756 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2758 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2760 pt.x = (squareSize - sz.cx) / 2;
\r
2761 pt.y = (squareSize - sz.cy) / 2;
\r
2763 SetBkMode( hdc, TRANSPARENT );
\r
2764 SetTextColor( hdc, chroma );
\r
2765 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2766 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2768 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2769 /* Step 3: the area outside the piece is filled with white */
\r
2770 // FloodFill( hdc, 0, 0, chroma );
\r
2771 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2772 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2773 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2774 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2775 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2777 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2778 but if the start point is not inside the piece we're lost!
\r
2779 There should be a better way to do this... if we could create a region or path
\r
2780 from the fill operation we would be fine for example.
\r
2782 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2783 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2785 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2786 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2787 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2789 SelectObject( dc2, bm2 );
\r
2790 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2791 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2792 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2793 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2794 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2797 DeleteObject( bm2 );
\r
2800 SetTextColor( hdc, 0 );
\r
2802 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2803 draw the piece again in black for safety.
\r
2805 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2807 SelectObject( hdc, hbm_old );
\r
2809 if( hPieceMask[index] != NULL ) {
\r
2810 DeleteObject( hPieceMask[index] );
\r
2813 hPieceMask[index] = hbm;
\r
2816 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2818 SelectObject( hdc, hbm );
\r
2821 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2822 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2823 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2825 SelectObject( dc1, hPieceMask[index] );
\r
2826 SelectObject( dc2, bm2 );
\r
2827 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2828 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2831 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2832 the piece background and deletes (makes transparent) the rest.
\r
2833 Thanks to that mask, we are free to paint the background with the greates
\r
2834 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2835 We use this, to make gradients and give the pieces a "roundish" look.
\r
2837 SetPieceBackground( hdc, backColor, 2 );
\r
2838 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2842 DeleteObject( bm2 );
\r
2845 SetTextColor( hdc, foreColor );
\r
2846 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2848 SelectObject( hdc, hbm_old );
\r
2850 if( hPieceFace[index] != NULL ) {
\r
2851 DeleteObject( hPieceFace[index] );
\r
2854 hPieceFace[index] = hbm;
\r
2857 static int TranslatePieceToFontPiece( int piece )
\r
2887 case BlackMarshall:
\r
2891 case BlackNightrider:
\r
2897 case BlackUnicorn:
\r
2901 case BlackGrasshopper:
\r
2913 case BlackCardinal:
\r
2920 case WhiteMarshall:
\r
2924 case WhiteNightrider:
\r
2930 case WhiteUnicorn:
\r
2934 case WhiteGrasshopper:
\r
2946 case WhiteCardinal:
\r
2955 void CreatePiecesFromFont()
\r
2958 HDC hdc_window = NULL;
\r
2964 if( fontBitmapSquareSize < 0 ) {
\r
2965 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2969 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2970 fontBitmapSquareSize = -1;
\r
2974 if( fontBitmapSquareSize != squareSize ) {
\r
2975 hdc_window = GetDC( hwndMain );
\r
2976 hdc = CreateCompatibleDC( hdc_window );
\r
2978 if( hPieceFont != NULL ) {
\r
2979 DeleteObject( hPieceFont );
\r
2982 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2983 hPieceMask[i] = NULL;
\r
2984 hPieceFace[i] = NULL;
\r
2990 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2991 fontHeight = appData.fontPieceSize;
\r
2994 fontHeight = (fontHeight * squareSize) / 100;
\r
2996 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2998 lf.lfEscapement = 0;
\r
2999 lf.lfOrientation = 0;
\r
3000 lf.lfWeight = FW_NORMAL;
\r
3002 lf.lfUnderline = 0;
\r
3003 lf.lfStrikeOut = 0;
\r
3004 lf.lfCharSet = DEFAULT_CHARSET;
\r
3005 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3006 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3007 lf.lfQuality = PROOF_QUALITY;
\r
3008 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3009 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3010 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3012 hPieceFont = CreateFontIndirect( &lf );
\r
3014 if( hPieceFont == NULL ) {
\r
3015 fontBitmapSquareSize = -2;
\r
3018 /* Setup font-to-piece character table */
\r
3019 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3020 /* No (or wrong) global settings, try to detect the font */
\r
3021 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3023 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3025 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3026 /* DiagramTT* family */
\r
3027 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3029 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3030 /* Fairy symbols */
\r
3031 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3033 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3034 /* Good Companion (Some characters get warped as literal :-( */
\r
3035 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3036 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3037 SetCharTable(pieceToFontChar, s);
\r
3040 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3041 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3045 /* Create bitmaps */
\r
3046 hfont_old = SelectObject( hdc, hPieceFont );
\r
3047 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3048 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3051 SelectObject( hdc, hfont_old );
\r
3053 fontBitmapSquareSize = squareSize;
\r
3057 if( hdc != NULL ) {
\r
3061 if( hdc_window != NULL ) {
\r
3062 ReleaseDC( hwndMain, hdc_window );
\r
3067 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3071 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3072 if (gameInfo.event &&
\r
3073 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3074 strcmp(name, "k80s") == 0) {
\r
3075 strcpy(name, "tim");
\r
3077 return LoadBitmap(hinst, name);
\r
3081 /* Insert a color into the program's logical palette
\r
3082 structure. This code assumes the given color is
\r
3083 the result of the RGB or PALETTERGB macro, and it
\r
3084 knows how those macros work (which is documented).
\r
3087 InsertInPalette(COLORREF color)
\r
3089 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3091 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3092 DisplayFatalError("Too many colors", 0, 1);
\r
3093 pLogPal->palNumEntries--;
\r
3097 pe->peFlags = (char) 0;
\r
3098 pe->peRed = (char) (0xFF & color);
\r
3099 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3100 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3106 InitDrawingColors()
\r
3108 if (pLogPal == NULL) {
\r
3109 /* Allocate enough memory for a logical palette with
\r
3110 * PALETTESIZE entries and set the size and version fields
\r
3111 * of the logical palette structure.
\r
3113 pLogPal = (NPLOGPALETTE)
\r
3114 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3115 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3116 pLogPal->palVersion = 0x300;
\r
3118 pLogPal->palNumEntries = 0;
\r
3120 InsertInPalette(lightSquareColor);
\r
3121 InsertInPalette(darkSquareColor);
\r
3122 InsertInPalette(whitePieceColor);
\r
3123 InsertInPalette(blackPieceColor);
\r
3124 InsertInPalette(highlightSquareColor);
\r
3125 InsertInPalette(premoveHighlightColor);
\r
3127 /* create a logical color palette according the information
\r
3128 * in the LOGPALETTE structure.
\r
3130 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3132 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3133 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3134 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3135 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3136 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3137 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3138 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3139 /* [AS] Force rendering of the font-based pieces */
\r
3140 if( fontBitmapSquareSize > 0 ) {
\r
3141 fontBitmapSquareSize = 0;
\r
3147 BoardWidth(int boardSize, int n)
\r
3148 { /* [HGM] argument n added to allow different width and height */
\r
3149 int lineGap = sizeInfo[boardSize].lineGap;
\r
3151 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3152 lineGap = appData.overrideLineGap;
\r
3155 return (n + 1) * lineGap +
\r
3156 n * sizeInfo[boardSize].squareSize;
\r
3159 /* Respond to board resize by dragging edge */
\r
3161 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3163 BoardSize newSize = NUM_SIZES - 1;
\r
3164 static int recurse = 0;
\r
3165 if (IsIconic(hwndMain)) return;
\r
3166 if (recurse > 0) return;
\r
3168 while (newSize > 0) {
\r
3169 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3170 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3171 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3174 boardSize = newSize;
\r
3175 InitDrawingSizes(boardSize, flags);
\r
3182 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3184 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3185 ChessSquare piece;
\r
3186 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3188 SIZE clockSize, messageSize;
\r
3190 char buf[MSG_SIZ];
\r
3192 HMENU hmenu = GetMenu(hwndMain);
\r
3193 RECT crect, wrect, oldRect;
\r
3195 LOGBRUSH logbrush;
\r
3197 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3198 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3200 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3201 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3203 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3204 oldRect.top = boardY;
\r
3205 oldRect.right = boardX + winWidth;
\r
3206 oldRect.bottom = boardY + winHeight;
\r
3208 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3209 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3210 squareSize = sizeInfo[boardSize].squareSize;
\r
3211 lineGap = sizeInfo[boardSize].lineGap;
\r
3212 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3214 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3215 lineGap = appData.overrideLineGap;
\r
3218 if (tinyLayout != oldTinyLayout) {
\r
3219 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3221 style &= ~WS_SYSMENU;
\r
3222 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3223 "&Minimize\tCtrl+F4");
\r
3225 style |= WS_SYSMENU;
\r
3226 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3228 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3230 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3231 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3232 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3234 DrawMenuBar(hwndMain);
\r
3237 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3238 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3240 /* Get text area sizes */
\r
3241 hdc = GetDC(hwndMain);
\r
3242 if (appData.clockMode) {
\r
3243 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3245 sprintf(buf, "White");
\r
3247 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3248 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3249 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3250 str = "We only care about the height here";
\r
3251 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3252 SelectObject(hdc, oldFont);
\r
3253 ReleaseDC(hwndMain, hdc);
\r
3255 /* Compute where everything goes */
\r
3256 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3257 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3258 logoHeight = 2*clockSize.cy;
\r
3259 leftLogoRect.left = OUTER_MARGIN;
\r
3260 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3261 leftLogoRect.top = OUTER_MARGIN;
\r
3262 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3264 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3265 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3266 rightLogoRect.top = OUTER_MARGIN;
\r
3267 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3270 whiteRect.left = leftLogoRect.right;
\r
3271 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3272 whiteRect.top = OUTER_MARGIN;
\r
3273 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3275 blackRect.right = rightLogoRect.left;
\r
3276 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3277 blackRect.top = whiteRect.top;
\r
3278 blackRect.bottom = whiteRect.bottom;
\r
3280 whiteRect.left = OUTER_MARGIN;
\r
3281 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3282 whiteRect.top = OUTER_MARGIN;
\r
3283 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3285 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3286 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3287 blackRect.top = whiteRect.top;
\r
3288 blackRect.bottom = whiteRect.bottom;
\r
3291 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3292 if (appData.showButtonBar) {
\r
3293 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3294 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3296 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3298 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3299 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3301 boardRect.left = OUTER_MARGIN;
\r
3302 boardRect.right = boardRect.left + boardWidth;
\r
3303 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3304 boardRect.bottom = boardRect.top + boardHeight;
\r
3306 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3307 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3308 oldBoardSize = boardSize;
\r
3309 oldTinyLayout = tinyLayout;
\r
3310 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3311 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3312 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3313 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3314 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3315 winHeight = winH; // without disturbing window attachments
\r
3316 GetWindowRect(hwndMain, &wrect);
\r
3317 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3318 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3320 // [HGM] placement: let attached windows follow size change.
\r
3321 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3322 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3323 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3324 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3325 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3327 /* compensate if menu bar wrapped */
\r
3328 GetClientRect(hwndMain, &crect);
\r
3329 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3330 winHeight += offby;
\r
3332 case WMSZ_TOPLEFT:
\r
3333 SetWindowPos(hwndMain, NULL,
\r
3334 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3335 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3338 case WMSZ_TOPRIGHT:
\r
3340 SetWindowPos(hwndMain, NULL,
\r
3341 wrect.left, wrect.bottom - winHeight,
\r
3342 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3345 case WMSZ_BOTTOMLEFT:
\r
3347 SetWindowPos(hwndMain, NULL,
\r
3348 wrect.right - winWidth, wrect.top,
\r
3349 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3352 case WMSZ_BOTTOMRIGHT:
\r
3356 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3357 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3362 for (i = 0; i < N_BUTTONS; i++) {
\r
3363 if (buttonDesc[i].hwnd != NULL) {
\r
3364 DestroyWindow(buttonDesc[i].hwnd);
\r
3365 buttonDesc[i].hwnd = NULL;
\r
3367 if (appData.showButtonBar) {
\r
3368 buttonDesc[i].hwnd =
\r
3369 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3370 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3371 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3372 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3373 (HMENU) buttonDesc[i].id,
\r
3374 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3376 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3377 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3378 MAKELPARAM(FALSE, 0));
\r
3380 if (buttonDesc[i].id == IDM_Pause)
\r
3381 hwndPause = buttonDesc[i].hwnd;
\r
3382 buttonDesc[i].wndproc = (WNDPROC)
\r
3383 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3386 if (gridPen != NULL) DeleteObject(gridPen);
\r
3387 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3388 if (premovePen != NULL) DeleteObject(premovePen);
\r
3389 if (lineGap != 0) {
\r
3390 logbrush.lbStyle = BS_SOLID;
\r
3391 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3393 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3394 lineGap, &logbrush, 0, NULL);
\r
3395 logbrush.lbColor = highlightSquareColor;
\r
3397 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3398 lineGap, &logbrush, 0, NULL);
\r
3400 logbrush.lbColor = premoveHighlightColor;
\r
3402 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3403 lineGap, &logbrush, 0, NULL);
\r
3405 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3406 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3407 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3408 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3409 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3410 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3411 BOARD_WIDTH * (squareSize + lineGap);
\r
3412 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3414 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3415 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3416 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3417 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3418 lineGap / 2 + (i * (squareSize + lineGap));
\r
3419 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3420 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3421 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3425 /* [HGM] Licensing requirement */
\r
3427 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3430 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3432 GothicPopUp( "", VariantNormal);
\r
3435 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3437 /* Load piece bitmaps for this board size */
\r
3438 for (i=0; i<=2; i++) {
\r
3439 for (piece = WhitePawn;
\r
3440 (int) piece < (int) BlackPawn;
\r
3441 piece = (ChessSquare) ((int) piece + 1)) {
\r
3442 if (pieceBitmap[i][piece] != NULL)
\r
3443 DeleteObject(pieceBitmap[i][piece]);
\r
3447 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3448 // Orthodox Chess pieces
\r
3449 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3450 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3451 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3452 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3453 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3454 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3455 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3456 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3457 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3458 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3459 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3460 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3461 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3462 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3463 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3464 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3465 // in Shogi, Hijack the unused Queen for Lance
\r
3466 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3467 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3468 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3470 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3475 if(squareSize <= 72 && squareSize >= 33) {
\r
3476 /* A & C are available in most sizes now */
\r
3477 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3478 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3479 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3480 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3481 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3482 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3483 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3484 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3485 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3486 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3487 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3488 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3489 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3490 } else { // Smirf-like
\r
3491 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3492 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3493 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3495 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3496 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3497 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3498 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3499 } else { // WinBoard standard
\r
3500 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3507 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3508 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3511 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3514 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3515 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3516 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3517 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3518 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3519 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3520 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3523 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3524 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3525 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3526 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3529 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3532 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3539 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3540 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3556 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3557 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3558 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3559 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3560 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3561 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3562 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3567 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3568 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3569 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3570 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3571 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3572 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3573 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3574 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3575 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3576 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3577 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3578 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3579 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3580 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3581 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3585 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3586 /* special Shogi support in this size */
\r
3587 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3588 for (piece = WhitePawn;
\r
3589 (int) piece < (int) BlackPawn;
\r
3590 piece = (ChessSquare) ((int) piece + 1)) {
\r
3591 if (pieceBitmap[i][piece] != NULL)
\r
3592 DeleteObject(pieceBitmap[i][piece]);
\r
3595 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3601 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3602 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3603 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3604 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3605 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3606 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3607 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3608 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3609 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3615 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3616 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3617 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3618 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3619 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3620 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3621 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3622 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3623 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3629 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3630 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3631 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3632 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3633 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3634 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3635 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3636 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3642 PieceBitmap(ChessSquare p, int kind)
\r
3644 if ((int) p >= (int) BlackPawn)
\r
3645 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3647 return pieceBitmap[kind][(int) p];
\r
3650 /***************************************************************/
\r
3652 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3653 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3655 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3656 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3660 SquareToPos(int row, int column, int * x, int * y)
\r
3663 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3664 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3666 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3667 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3672 DrawCoordsOnDC(HDC hdc)
\r
3674 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
3675 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
3676 char str[2] = { NULLCHAR, NULLCHAR };
\r
3677 int oldMode, oldAlign, x, y, start, i;
\r
3681 if (!appData.showCoords)
\r
3684 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3686 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3687 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3688 oldAlign = GetTextAlign(hdc);
\r
3689 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3691 y = boardRect.top + lineGap;
\r
3692 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3694 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3695 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3696 str[0] = files[start + i];
\r
3697 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3698 y += squareSize + lineGap;
\r
3701 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3703 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3704 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3705 str[0] = ranks[start + i];
\r
3706 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3707 x += squareSize + lineGap;
\r
3710 SelectObject(hdc, oldBrush);
\r
3711 SetBkMode(hdc, oldMode);
\r
3712 SetTextAlign(hdc, oldAlign);
\r
3713 SelectObject(hdc, oldFont);
\r
3717 DrawGridOnDC(HDC hdc)
\r
3721 if (lineGap != 0) {
\r
3722 oldPen = SelectObject(hdc, gridPen);
\r
3723 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3724 SelectObject(hdc, oldPen);
\r
3728 #define HIGHLIGHT_PEN 0
\r
3729 #define PREMOVE_PEN 1
\r
3732 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3735 HPEN oldPen, hPen;
\r
3736 if (lineGap == 0) return;
\r
3738 x1 = boardRect.left +
\r
3739 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3740 y1 = boardRect.top +
\r
3741 lineGap/2 + y * (squareSize + lineGap);
\r
3743 x1 = boardRect.left +
\r
3744 lineGap/2 + x * (squareSize + lineGap);
\r
3745 y1 = boardRect.top +
\r
3746 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3748 hPen = pen ? premovePen : highlightPen;
\r
3749 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3750 MoveToEx(hdc, x1, y1, NULL);
\r
3751 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3752 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3753 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3754 LineTo(hdc, x1, y1);
\r
3755 SelectObject(hdc, oldPen);
\r
3759 DrawHighlightsOnDC(HDC hdc)
\r
3762 for (i=0; i<2; i++) {
\r
3763 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3764 DrawHighlightOnDC(hdc, TRUE,
\r
3765 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3768 for (i=0; i<2; i++) {
\r
3769 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3770 premoveHighlightInfo.sq[i].y >= 0) {
\r
3771 DrawHighlightOnDC(hdc, TRUE,
\r
3772 premoveHighlightInfo.sq[i].x,
\r
3773 premoveHighlightInfo.sq[i].y,
\r
3779 /* Note: sqcolor is used only in monoMode */
\r
3780 /* Note that this code is largely duplicated in woptions.c,
\r
3781 function DrawSampleSquare, so that needs to be updated too */
\r
3783 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3785 HBITMAP oldBitmap;
\r
3789 if (appData.blindfold) return;
\r
3791 /* [AS] Use font-based pieces if needed */
\r
3792 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3793 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3794 CreatePiecesFromFont();
\r
3796 if( fontBitmapSquareSize == squareSize ) {
\r
3797 int index = TranslatePieceToFontPiece(piece);
\r
3799 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3803 squareSize, squareSize,
\r
3808 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3812 squareSize, squareSize,
\r
3821 if (appData.monoMode) {
\r
3822 SelectObject(tmphdc, PieceBitmap(piece,
\r
3823 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3824 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3825 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3827 tmpSize = squareSize;
\r
3829 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3830 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3831 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3832 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3833 x += (squareSize - minorSize)>>1;
\r
3834 y += squareSize - minorSize - 2;
\r
3835 tmpSize = minorSize;
\r
3837 if (color || appData.allWhite ) {
\r
3838 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3840 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3841 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3842 if(appData.upsideDown && color==flipView)
\r
3843 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3845 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3846 /* Use black for outline of white pieces */
\r
3847 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3848 if(appData.upsideDown && color==flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3853 /* Use square color for details of black pieces */
\r
3854 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3855 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3856 if(appData.upsideDown && !flipView)
\r
3857 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3859 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3861 SelectObject(hdc, oldBrush);
\r
3862 SelectObject(tmphdc, oldBitmap);
\r
3866 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3867 int GetBackTextureMode( int algo )
\r
3869 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3873 case BACK_TEXTURE_MODE_PLAIN:
\r
3874 result = 1; /* Always use identity map */
\r
3876 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3877 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3885 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3886 to handle redraws cleanly (as random numbers would always be different).
\r
3888 VOID RebuildTextureSquareInfo()
\r
3898 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3900 if( liteBackTexture != NULL ) {
\r
3901 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3902 lite_w = bi.bmWidth;
\r
3903 lite_h = bi.bmHeight;
\r
3907 if( darkBackTexture != NULL ) {
\r
3908 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3909 dark_w = bi.bmWidth;
\r
3910 dark_h = bi.bmHeight;
\r
3914 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3915 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3916 if( (col + row) & 1 ) {
\r
3918 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3926 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3927 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3928 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3929 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3936 /* [AS] Arrow highlighting support */
\r
3938 static int A_WIDTH = 5; /* Width of arrow body */
\r
3940 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3941 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3943 static double Sqr( double x )
\r
3948 static int Round( double x )
\r
3950 return (int) (x + 0.5);
\r
3953 /* Draw an arrow between two points using current settings */
\r
3954 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3957 double dx, dy, j, k, x, y;
\r
3959 if( d_x == s_x ) {
\r
3960 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3962 arrow[0].x = s_x + A_WIDTH;
\r
3965 arrow[1].x = s_x + A_WIDTH;
\r
3966 arrow[1].y = d_y - h;
\r
3968 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3969 arrow[2].y = d_y - h;
\r
3974 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3975 arrow[4].y = d_y - h;
\r
3977 arrow[5].x = s_x - A_WIDTH;
\r
3978 arrow[5].y = d_y - h;
\r
3980 arrow[6].x = s_x - A_WIDTH;
\r
3983 else if( d_y == s_y ) {
\r
3984 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3987 arrow[0].y = s_y + A_WIDTH;
\r
3989 arrow[1].x = d_x - w;
\r
3990 arrow[1].y = s_y + A_WIDTH;
\r
3992 arrow[2].x = d_x - w;
\r
3993 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3998 arrow[4].x = d_x - w;
\r
3999 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4001 arrow[5].x = d_x - w;
\r
4002 arrow[5].y = s_y - A_WIDTH;
\r
4005 arrow[6].y = s_y - A_WIDTH;
\r
4008 /* [AS] Needed a lot of paper for this! :-) */
\r
4009 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4010 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4012 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4014 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4019 arrow[0].x = Round(x - j);
\r
4020 arrow[0].y = Round(y + j*dx);
\r
4022 arrow[1].x = Round(x + j);
\r
4023 arrow[1].y = Round(y - j*dx);
\r
4026 x = (double) d_x - k;
\r
4027 y = (double) d_y - k*dy;
\r
4030 x = (double) d_x + k;
\r
4031 y = (double) d_y + k*dy;
\r
4034 arrow[2].x = Round(x + j);
\r
4035 arrow[2].y = Round(y - j*dx);
\r
4037 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4038 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4043 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4044 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4046 arrow[6].x = Round(x - j);
\r
4047 arrow[6].y = Round(y + j*dx);
\r
4050 Polygon( hdc, arrow, 7 );
\r
4053 /* [AS] Draw an arrow between two squares */
\r
4054 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4056 int s_x, s_y, d_x, d_y;
\r
4063 if( s_col == d_col && s_row == d_row ) {
\r
4067 /* Get source and destination points */
\r
4068 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4069 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4072 d_y += squareSize / 4;
\r
4074 else if( d_y < s_y ) {
\r
4075 d_y += 3 * squareSize / 4;
\r
4078 d_y += squareSize / 2;
\r
4082 d_x += squareSize / 4;
\r
4084 else if( d_x < s_x ) {
\r
4085 d_x += 3 * squareSize / 4;
\r
4088 d_x += squareSize / 2;
\r
4091 s_x += squareSize / 2;
\r
4092 s_y += squareSize / 2;
\r
4094 /* Adjust width */
\r
4095 A_WIDTH = squareSize / 14;
\r
4098 stLB.lbStyle = BS_SOLID;
\r
4099 stLB.lbColor = appData.highlightArrowColor;
\r
4102 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4103 holdpen = SelectObject( hdc, hpen );
\r
4104 hbrush = CreateBrushIndirect( &stLB );
\r
4105 holdbrush = SelectObject( hdc, hbrush );
\r
4107 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4109 SelectObject( hdc, holdpen );
\r
4110 SelectObject( hdc, holdbrush );
\r
4111 DeleteObject( hpen );
\r
4112 DeleteObject( hbrush );
\r
4115 BOOL HasHighlightInfo()
\r
4117 BOOL result = FALSE;
\r
4119 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4120 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4128 BOOL IsDrawArrowEnabled()
\r
4130 BOOL result = FALSE;
\r
4132 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4139 VOID DrawArrowHighlight( HDC hdc )
\r
4141 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4142 DrawArrowBetweenSquares( hdc,
\r
4143 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4144 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4148 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4150 HRGN result = NULL;
\r
4152 if( HasHighlightInfo() ) {
\r
4153 int x1, y1, x2, y2;
\r
4154 int sx, sy, dx, dy;
\r
4156 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4157 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4159 sx = MIN( x1, x2 );
\r
4160 sy = MIN( y1, y2 );
\r
4161 dx = MAX( x1, x2 ) + squareSize;
\r
4162 dy = MAX( y1, y2 ) + squareSize;
\r
4164 result = CreateRectRgn( sx, sy, dx, dy );
\r
4171 Warning: this function modifies the behavior of several other functions.
\r
4173 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4174 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4175 repaint is scattered all over the place, which is not good for features such as
\r
4176 "arrow highlighting" that require a full repaint of the board.
\r
4178 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4179 user interaction, when speed is not so important) but especially to avoid errors
\r
4180 in the displayed graphics.
\r
4182 In such patched places, I always try refer to this function so there is a single
\r
4183 place to maintain knowledge.
\r
4185 To restore the original behavior, just return FALSE unconditionally.
\r
4187 BOOL IsFullRepaintPreferrable()
\r
4189 BOOL result = FALSE;
\r
4191 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4192 /* Arrow may appear on the board */
\r
4200 This function is called by DrawPosition to know whether a full repaint must
\r
4203 Only DrawPosition may directly call this function, which makes use of
\r
4204 some state information. Other function should call DrawPosition specifying
\r
4205 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4207 BOOL DrawPositionNeedsFullRepaint()
\r
4209 BOOL result = FALSE;
\r
4212 Probably a slightly better policy would be to trigger a full repaint
\r
4213 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4214 but animation is fast enough that it's difficult to notice.
\r
4216 if( animInfo.piece == EmptySquare ) {
\r
4217 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4226 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4228 int row, column, x, y, square_color, piece_color;
\r
4229 ChessSquare piece;
\r
4231 HDC texture_hdc = NULL;
\r
4233 /* [AS] Initialize background textures if needed */
\r
4234 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4235 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4236 if( backTextureSquareSize != squareSize
\r
4237 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4238 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4239 backTextureSquareSize = squareSize;
\r
4240 RebuildTextureSquareInfo();
\r
4243 texture_hdc = CreateCompatibleDC( hdc );
\r
4246 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4247 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4249 SquareToPos(row, column, &x, &y);
\r
4251 piece = board[row][column];
\r
4253 square_color = ((column + row) % 2) == 1;
\r
4254 if( gameInfo.variant == VariantXiangqi ) {
\r
4255 square_color = !InPalace(row, column);
\r
4256 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4257 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4259 piece_color = (int) piece < (int) BlackPawn;
\r
4262 /* [HGM] holdings file: light square or black */
\r
4263 if(column == BOARD_LEFT-2) {
\r
4264 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4271 if(column == BOARD_RGHT + 1 ) {
\r
4272 if( row < gameInfo.holdingsSize )
\r
4275 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4279 if(column == BOARD_LEFT-1 ) /* left align */
\r
4280 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4281 else if( column == BOARD_RGHT) /* right align */
\r
4282 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4284 if (appData.monoMode) {
\r
4285 if (piece == EmptySquare) {
\r
4286 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4287 square_color ? WHITENESS : BLACKNESS);
\r
4289 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4292 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4293 /* [AS] Draw the square using a texture bitmap */
\r
4294 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4295 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4296 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4299 squareSize, squareSize,
\r
4302 backTextureSquareInfo[r][c].mode,
\r
4303 backTextureSquareInfo[r][c].x,
\r
4304 backTextureSquareInfo[r][c].y );
\r
4306 SelectObject( texture_hdc, hbm );
\r
4308 if (piece != EmptySquare) {
\r
4309 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4313 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4315 oldBrush = SelectObject(hdc, brush );
\r
4316 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4317 SelectObject(hdc, oldBrush);
\r
4318 if (piece != EmptySquare)
\r
4319 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4324 if( texture_hdc != NULL ) {
\r
4325 DeleteDC( texture_hdc );
\r
4329 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4330 void fputDW(FILE *f, int x)
\r
4332 fputc(x & 255, f);
\r
4333 fputc(x>>8 & 255, f);
\r
4334 fputc(x>>16 & 255, f);
\r
4335 fputc(x>>24 & 255, f);
\r
4338 #define MAX_CLIPS 200 /* more than enough */
\r
4341 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4343 // HBITMAP bufferBitmap;
\r
4348 int w = 100, h = 50;
\r
4350 if(logo == NULL) return;
\r
4351 // GetClientRect(hwndMain, &Rect);
\r
4352 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4353 // Rect.bottom-Rect.top+1);
\r
4354 tmphdc = CreateCompatibleDC(hdc);
\r
4355 hbm = SelectObject(tmphdc, logo);
\r
4356 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4360 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4361 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4362 SelectObject(tmphdc, hbm);
\r
4367 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4369 static Board lastReq, lastDrawn;
\r
4370 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4371 static int lastDrawnFlipView = 0;
\r
4372 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4373 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4376 HBITMAP bufferBitmap;
\r
4377 HBITMAP oldBitmap;
\r
4379 HRGN clips[MAX_CLIPS];
\r
4380 ChessSquare dragged_piece = EmptySquare;
\r
4382 /* I'm undecided on this - this function figures out whether a full
\r
4383 * repaint is necessary on its own, so there's no real reason to have the
\r
4384 * caller tell it that. I think this can safely be set to FALSE - but
\r
4385 * if we trust the callers not to request full repaints unnessesarily, then
\r
4386 * we could skip some clipping work. In other words, only request a full
\r
4387 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4388 * gamestart and similar) --Hawk
\r
4390 Boolean fullrepaint = repaint;
\r
4392 if( DrawPositionNeedsFullRepaint() ) {
\r
4393 fullrepaint = TRUE;
\r
4396 if (board == NULL) {
\r
4397 if (!lastReqValid) {
\r
4402 CopyBoard(lastReq, board);
\r
4406 if (doingSizing) {
\r
4410 if (IsIconic(hwndMain)) {
\r
4414 if (hdc == NULL) {
\r
4415 hdc = GetDC(hwndMain);
\r
4416 if (!appData.monoMode) {
\r
4417 SelectPalette(hdc, hPal, FALSE);
\r
4418 RealizePalette(hdc);
\r
4422 releaseDC = FALSE;
\r
4425 /* Create some work-DCs */
\r
4426 hdcmem = CreateCompatibleDC(hdc);
\r
4427 tmphdc = CreateCompatibleDC(hdc);
\r
4429 /* If dragging is in progress, we temporarely remove the piece */
\r
4430 /* [HGM] or temporarily decrease count if stacked */
\r
4431 /* !! Moved to before board compare !! */
\r
4432 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4433 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4434 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4435 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4436 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4438 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4439 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4440 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4442 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4445 /* Figure out which squares need updating by comparing the
\r
4446 * newest board with the last drawn board and checking if
\r
4447 * flipping has changed.
\r
4449 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4450 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4451 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4452 if (lastDrawn[row][column] != board[row][column]) {
\r
4453 SquareToPos(row, column, &x, &y);
\r
4454 clips[num_clips++] =
\r
4455 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4459 for (i=0; i<2; i++) {
\r
4460 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4461 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4462 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4463 lastDrawnHighlight.sq[i].y >= 0) {
\r
4464 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4465 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4466 clips[num_clips++] =
\r
4467 CreateRectRgn(x - lineGap, y - lineGap,
\r
4468 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4471 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4472 clips[num_clips++] =
\r
4473 CreateRectRgn(x - lineGap, y - lineGap,
\r
4474 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4478 for (i=0; i<2; i++) {
\r
4479 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4480 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4481 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4482 lastDrawnPremove.sq[i].y >= 0) {
\r
4483 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4484 lastDrawnPremove.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4489 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4490 premoveHighlightInfo.sq[i].y >= 0) {
\r
4491 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4492 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4493 clips[num_clips++] =
\r
4494 CreateRectRgn(x - lineGap, y - lineGap,
\r
4495 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4500 fullrepaint = TRUE;
\r
4503 /* Create a buffer bitmap - this is the actual bitmap
\r
4504 * being written to. When all the work is done, we can
\r
4505 * copy it to the real DC (the screen). This avoids
\r
4506 * the problems with flickering.
\r
4508 GetClientRect(hwndMain, &Rect);
\r
4509 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4510 Rect.bottom-Rect.top+1);
\r
4511 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4512 if (!appData.monoMode) {
\r
4513 SelectPalette(hdcmem, hPal, FALSE);
\r
4516 /* Create clips for dragging */
\r
4517 if (!fullrepaint) {
\r
4518 if (dragInfo.from.x >= 0) {
\r
4519 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4520 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4522 if (dragInfo.start.x >= 0) {
\r
4523 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4524 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4526 if (dragInfo.pos.x >= 0) {
\r
4527 x = dragInfo.pos.x - squareSize / 2;
\r
4528 y = dragInfo.pos.y - squareSize / 2;
\r
4529 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4531 if (dragInfo.lastpos.x >= 0) {
\r
4532 x = dragInfo.lastpos.x - squareSize / 2;
\r
4533 y = dragInfo.lastpos.y - squareSize / 2;
\r
4534 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4538 /* Are we animating a move?
\r
4540 * - remove the piece from the board (temporarely)
\r
4541 * - calculate the clipping region
\r
4543 if (!fullrepaint) {
\r
4544 if (animInfo.piece != EmptySquare) {
\r
4545 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4546 x = boardRect.left + animInfo.lastpos.x;
\r
4547 y = boardRect.top + animInfo.lastpos.y;
\r
4548 x2 = boardRect.left + animInfo.pos.x;
\r
4549 y2 = boardRect.top + animInfo.pos.y;
\r
4550 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4551 /* Slight kludge. The real problem is that after AnimateMove is
\r
4552 done, the position on the screen does not match lastDrawn.
\r
4553 This currently causes trouble only on e.p. captures in
\r
4554 atomic, where the piece moves to an empty square and then
\r
4555 explodes. The old and new positions both had an empty square
\r
4556 at the destination, but animation has drawn a piece there and
\r
4557 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4558 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4562 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4563 if (num_clips == 0)
\r
4564 fullrepaint = TRUE;
\r
4566 /* Set clipping on the memory DC */
\r
4567 if (!fullrepaint) {
\r
4568 SelectClipRgn(hdcmem, clips[0]);
\r
4569 for (x = 1; x < num_clips; x++) {
\r
4570 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4571 abort(); // this should never ever happen!
\r
4575 /* Do all the drawing to the memory DC */
\r
4576 if(explodeInfo.radius) { // [HGM] atomic
\r
4578 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4579 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4580 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4581 x += squareSize/2;
\r
4582 y += squareSize/2;
\r
4583 if(!fullrepaint) {
\r
4584 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4585 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4587 DrawGridOnDC(hdcmem);
\r
4588 DrawHighlightsOnDC(hdcmem);
\r
4589 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4590 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4591 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4592 SelectObject(hdcmem, oldBrush);
\r
4594 DrawGridOnDC(hdcmem);
\r
4595 DrawHighlightsOnDC(hdcmem);
\r
4596 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4599 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4600 if(appData.autoLogo) {
\r
4602 switch(gameMode) { // pick logos based on game mode
\r
4603 case IcsObserving:
\r
4604 whiteLogo = second.programLogo; // ICS logo
\r
4605 blackLogo = second.programLogo;
\r
4608 case IcsPlayingWhite:
\r
4609 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4610 blackLogo = second.programLogo; // ICS logo
\r
4612 case IcsPlayingBlack:
\r
4613 whiteLogo = second.programLogo; // ICS logo
\r
4614 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4616 case TwoMachinesPlay:
\r
4617 if(first.twoMachinesColor[0] == 'b') {
\r
4618 whiteLogo = second.programLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 case MachinePlaysWhite:
\r
4623 blackLogo = userLogo;
\r
4625 case MachinePlaysBlack:
\r
4626 whiteLogo = userLogo;
\r
4627 blackLogo = first.programLogo;
\r
4630 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4631 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4634 if( appData.highlightMoveWithArrow ) {
\r
4635 DrawArrowHighlight(hdcmem);
\r
4638 DrawCoordsOnDC(hdcmem);
\r
4640 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4641 /* to make sure lastDrawn contains what is actually drawn */
\r
4643 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4644 if (dragged_piece != EmptySquare) {
\r
4645 /* [HGM] or restack */
\r
4646 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4647 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4649 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4650 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4651 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4652 x = dragInfo.pos.x - squareSize / 2;
\r
4653 y = dragInfo.pos.y - squareSize / 2;
\r
4654 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4655 ((int) dragged_piece < (int) BlackPawn),
\r
4656 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4659 /* Put the animated piece back into place and draw it */
\r
4660 if (animInfo.piece != EmptySquare) {
\r
4661 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4662 x = boardRect.left + animInfo.pos.x;
\r
4663 y = boardRect.top + animInfo.pos.y;
\r
4664 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4665 ((int) animInfo.piece < (int) BlackPawn),
\r
4666 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4669 /* Release the bufferBitmap by selecting in the old bitmap
\r
4670 * and delete the memory DC
\r
4672 SelectObject(hdcmem, oldBitmap);
\r
4675 /* Set clipping on the target DC */
\r
4676 if (!fullrepaint) {
\r
4677 SelectClipRgn(hdc, clips[0]);
\r
4678 for (x = 1; x < num_clips; x++) {
\r
4679 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4680 abort(); // this should never ever happen!
\r
4684 /* Copy the new bitmap onto the screen in one go.
\r
4685 * This way we avoid any flickering
\r
4687 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4688 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4689 boardRect.right - boardRect.left,
\r
4690 boardRect.bottom - boardRect.top,
\r
4691 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4692 if(saveDiagFlag) {
\r
4693 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4694 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4696 GetObject(bufferBitmap, sizeof(b), &b);
\r
4697 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4698 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4699 bih.biWidth = b.bmWidth;
\r
4700 bih.biHeight = b.bmHeight;
\r
4702 bih.biBitCount = b.bmBitsPixel;
\r
4703 bih.biCompression = 0;
\r
4704 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4705 bih.biXPelsPerMeter = 0;
\r
4706 bih.biYPelsPerMeter = 0;
\r
4707 bih.biClrUsed = 0;
\r
4708 bih.biClrImportant = 0;
\r
4709 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4710 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4711 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4712 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4714 wb = b.bmWidthBytes;
\r
4716 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4717 int k = ((int*) pData)[i];
\r
4718 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4719 if(j >= 16) break;
\r
4721 if(j >= nrColors) nrColors = j+1;
\r
4723 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4725 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4726 for(w=0; w<(wb>>2); w+=2) {
\r
4727 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4728 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4729 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4730 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4731 pData[p++] = m | j<<4;
\r
4733 while(p&3) pData[p++] = 0;
\r
4736 wb = ((wb+31)>>5)<<2;
\r
4738 // write BITMAPFILEHEADER
\r
4739 fprintf(diagFile, "BM");
\r
4740 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4743 // write BITMAPINFOHEADER
\r
4744 fputDW(diagFile, 40);
\r
4745 fputDW(diagFile, b.bmWidth);
\r
4746 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4747 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4748 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4749 fputDW(diagFile, 0);
\r
4750 fputDW(diagFile, 0);
\r
4751 fputDW(diagFile, 0);
\r
4752 fputDW(diagFile, 0);
\r
4753 fputDW(diagFile, 0);
\r
4754 fputDW(diagFile, 0);
\r
4755 // write color table
\r
4757 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4758 // write bitmap data
\r
4759 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4760 fputc(pData[i], diagFile);
\r
4764 SelectObject(tmphdc, oldBitmap);
\r
4766 /* Massive cleanup */
\r
4767 for (x = 0; x < num_clips; x++)
\r
4768 DeleteObject(clips[x]);
\r
4771 DeleteObject(bufferBitmap);
\r
4774 ReleaseDC(hwndMain, hdc);
\r
4776 if (lastDrawnFlipView != flipView) {
\r
4778 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4780 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4783 /* CopyBoard(lastDrawn, board);*/
\r
4784 lastDrawnHighlight = highlightInfo;
\r
4785 lastDrawnPremove = premoveHighlightInfo;
\r
4786 lastDrawnFlipView = flipView;
\r
4787 lastDrawnValid = 1;
\r
4790 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4795 saveDiagFlag = 1; diagFile = f;
\r
4796 HDCDrawPosition(NULL, TRUE, NULL);
\r
4800 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4807 /*---------------------------------------------------------------------------*\
\r
4808 | CLIENT PAINT PROCEDURE
\r
4809 | This is the main event-handler for the WM_PAINT message.
\r
4811 \*---------------------------------------------------------------------------*/
\r
4813 PaintProc(HWND hwnd)
\r
4819 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4820 if (IsIconic(hwnd)) {
\r
4821 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4823 if (!appData.monoMode) {
\r
4824 SelectPalette(hdc, hPal, FALSE);
\r
4825 RealizePalette(hdc);
\r
4827 HDCDrawPosition(hdc, 1, NULL);
\r
4829 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4830 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4831 ETO_CLIPPED|ETO_OPAQUE,
\r
4832 &messageRect, messageText, strlen(messageText), NULL);
\r
4833 SelectObject(hdc, oldFont);
\r
4834 DisplayBothClocks();
\r
4836 EndPaint(hwnd,&ps);
\r
4844 * If the user selects on a border boundary, return -1; if off the board,
\r
4845 * return -2. Otherwise map the event coordinate to the square.
\r
4846 * The offset boardRect.left or boardRect.top must already have been
\r
4847 * subtracted from x.
\r
4849 int EventToSquare(x, limit)
\r
4857 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4859 x /= (squareSize + lineGap);
\r
4871 DropEnable dropEnables[] = {
\r
4872 { 'P', DP_Pawn, "Pawn" },
\r
4873 { 'N', DP_Knight, "Knight" },
\r
4874 { 'B', DP_Bishop, "Bishop" },
\r
4875 { 'R', DP_Rook, "Rook" },
\r
4876 { 'Q', DP_Queen, "Queen" },
\r
4880 SetupDropMenu(HMENU hmenu)
\r
4882 int i, count, enable;
\r
4884 extern char white_holding[], black_holding[];
\r
4885 char item[MSG_SIZ];
\r
4887 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4888 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4889 dropEnables[i].piece);
\r
4891 while (p && *p++ == dropEnables[i].piece) count++;
\r
4892 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4893 enable = count > 0 || !appData.testLegality
\r
4894 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4895 && !appData.icsActive);
\r
4896 ModifyMenu(hmenu, dropEnables[i].command,
\r
4897 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4898 dropEnables[i].command, item);
\r
4902 void DragPieceBegin(int x, int y)
\r
4904 dragInfo.lastpos.x = boardRect.left + x;
\r
4905 dragInfo.lastpos.y = boardRect.top + y;
\r
4906 dragInfo.from.x = fromX;
\r
4907 dragInfo.from.y = fromY;
\r
4908 dragInfo.start = dragInfo.from;
\r
4909 SetCapture(hwndMain);
\r
4912 void DragPieceEnd(int x, int y)
\r
4915 dragInfo.start.x = dragInfo.start.y = -1;
\r
4916 dragInfo.from = dragInfo.start;
\r
4917 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4920 /* Event handler for mouse messages */
\r
4922 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4926 static int recursive = 0;
\r
4928 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4931 if (message == WM_MBUTTONUP) {
\r
4932 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4933 to the middle button: we simulate pressing the left button too!
\r
4935 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4936 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4942 pt.x = LOWORD(lParam);
\r
4943 pt.y = HIWORD(lParam);
\r
4944 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4945 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4946 if (!flipView && y >= 0) {
\r
4947 y = BOARD_HEIGHT - 1 - y;
\r
4949 if (flipView && x >= 0) {
\r
4950 x = BOARD_WIDTH - 1 - x;
\r
4953 switch (message) {
\r
4954 case WM_LBUTTONDOWN:
\r
4955 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4956 if (gameMode == EditPosition) {
\r
4957 SetWhiteToPlayEvent();
\r
4958 } else if (gameMode == IcsPlayingBlack ||
\r
4959 gameMode == MachinePlaysWhite) {
\r
4961 } else if (gameMode == EditGame) {
\r
4962 AdjustClock(flipClock, -1);
\r
4964 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4965 if (gameMode == EditPosition) {
\r
4966 SetBlackToPlayEvent();
\r
4967 } else if (gameMode == IcsPlayingWhite ||
\r
4968 gameMode == MachinePlaysBlack) {
\r
4970 } else if (gameMode == EditGame) {
\r
4971 AdjustClock(!flipClock, -1);
\r
4974 dragInfo.start.x = dragInfo.start.y = -1;
\r
4975 dragInfo.from = dragInfo.start;
\r
4976 if(fromX == -1 && frozen) { // not sure where this is for
\r
4977 fromX = fromY = -1;
\r
4978 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4981 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4982 DrawPosition(TRUE, NULL);
\r
4985 case WM_LBUTTONUP:
\r
4986 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4987 DrawPosition(TRUE, NULL);
\r
4990 case WM_MOUSEMOVE:
\r
4991 if ((appData.animateDragging || appData.highlightDragging)
\r
4992 && (wParam & MK_LBUTTON)
\r
4993 && dragInfo.from.x >= 0)
\r
4995 BOOL full_repaint = FALSE;
\r
4997 if (appData.animateDragging) {
\r
4998 dragInfo.pos = pt;
\r
5000 if (appData.highlightDragging) {
\r
5001 SetHighlights(fromX, fromY, x, y);
\r
5002 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5003 full_repaint = TRUE;
\r
5007 DrawPosition( full_repaint, NULL);
\r
5009 dragInfo.lastpos = dragInfo.pos;
\r
5013 case WM_MOUSEWHEEL: // [DM]
\r
5014 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5015 /* Mouse Wheel is being rolled forward
\r
5016 * Play moves forward
\r
5018 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5019 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5020 /* Mouse Wheel is being rolled backward
\r
5021 * Play moves backward
\r
5023 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5024 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5028 case WM_MBUTTONDOWN:
\r
5029 case WM_RBUTTONDOWN:
\r
5032 fromX = fromY = -1;
\r
5033 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5034 dragInfo.start.x = dragInfo.start.y = -1;
\r
5035 dragInfo.from = dragInfo.start;
\r
5036 dragInfo.lastpos = dragInfo.pos;
\r
5037 if (appData.highlightDragging) {
\r
5038 ClearHighlights();
\r
5041 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5042 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5043 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5044 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5045 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5048 DrawPosition(TRUE, NULL);
\r
5050 switch (gameMode) {
\r
5051 case EditPosition:
\r
5052 case IcsExamining:
\r
5053 if (x < 0 || y < 0) break;
\r
5056 if (message == WM_MBUTTONDOWN) {
\r
5057 buttonCount = 3; /* even if system didn't think so */
\r
5058 if (wParam & MK_SHIFT)
\r
5059 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5061 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5062 } else { /* message == WM_RBUTTONDOWN */
\r
5063 /* Just have one menu, on the right button. Windows users don't
\r
5064 think to try the middle one, and sometimes other software steals
\r
5065 it, or it doesn't really exist. */
\r
5066 if(gameInfo.variant != VariantShogi)
\r
5067 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5069 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5072 case IcsPlayingWhite:
\r
5073 case IcsPlayingBlack:
\r
5075 case MachinePlaysWhite:
\r
5076 case MachinePlaysBlack:
\r
5077 if (appData.testLegality &&
\r
5078 gameInfo.variant != VariantBughouse &&
\r
5079 gameInfo.variant != VariantCrazyhouse) break;
\r
5080 if (x < 0 || y < 0) break;
\r
5083 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5084 SetupDropMenu(hmenu);
\r
5085 MenuPopup(hwnd, pt, hmenu, -1);
\r
5096 /* Preprocess messages for buttons in main window */
\r
5098 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5100 int id = GetWindowLong(hwnd, GWL_ID);
\r
5103 for (i=0; i<N_BUTTONS; i++) {
\r
5104 if (buttonDesc[i].id == id) break;
\r
5106 if (i == N_BUTTONS) return 0;
\r
5107 switch (message) {
\r
5112 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5113 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5120 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5123 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5124 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5125 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5126 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5128 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5130 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5131 PopUpMoveDialog((char)wParam);
\r
5137 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5140 /* Process messages for Promotion dialog box */
\r
5142 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5146 switch (message) {
\r
5147 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5148 /* Center the dialog over the application window */
\r
5149 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5150 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5151 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5152 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5153 SW_SHOW : SW_HIDE);
\r
5154 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5155 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5156 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5157 PieceToChar(WhiteAngel) != '~') ||
\r
5158 (PieceToChar(BlackAngel) >= 'A' &&
\r
5159 PieceToChar(BlackAngel) != '~') ) ?
\r
5160 SW_SHOW : SW_HIDE);
\r
5161 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5162 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5163 PieceToChar(WhiteMarshall) != '~') ||
\r
5164 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5165 PieceToChar(BlackMarshall) != '~') ) ?
\r
5166 SW_SHOW : SW_HIDE);
\r
5167 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5168 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5169 gameInfo.variant != VariantShogi ?
\r
5170 SW_SHOW : SW_HIDE);
\r
5171 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5172 gameInfo.variant != VariantShogi ?
\r
5173 SW_SHOW : SW_HIDE);
\r
5174 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5175 gameInfo.variant == VariantShogi ?
\r
5176 SW_SHOW : SW_HIDE);
\r
5177 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5178 gameInfo.variant == VariantShogi ?
\r
5179 SW_SHOW : SW_HIDE);
\r
5180 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5181 gameInfo.variant == VariantSuper ?
\r
5182 SW_SHOW : SW_HIDE);
\r
5185 case WM_COMMAND: /* message: received a command */
\r
5186 switch (LOWORD(wParam)) {
\r
5188 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5189 ClearHighlights();
\r
5190 DrawPosition(FALSE, NULL);
\r
5193 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5196 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5199 promoChar = PieceToChar(BlackRook);
\r
5202 promoChar = PieceToChar(BlackBishop);
\r
5204 case PB_Chancellor:
\r
5205 promoChar = PieceToChar(BlackMarshall);
\r
5207 case PB_Archbishop:
\r
5208 promoChar = PieceToChar(BlackAngel);
\r
5211 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5216 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5217 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5218 only show the popup when we are already sure the move is valid or
\r
5219 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5220 will figure out it is a promotion from the promoChar. */
\r
5221 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5222 fromX = fromY = -1;
\r
5223 if (!appData.highlightLastMove) {
\r
5224 ClearHighlights();
\r
5225 DrawPosition(FALSE, NULL);
\r
5232 /* Pop up promotion dialog */
\r
5234 PromotionPopup(HWND hwnd)
\r
5238 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5239 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5240 hwnd, (DLGPROC)lpProc);
\r
5241 FreeProcInstance(lpProc);
\r
5247 DrawPosition(TRUE, NULL);
\r
5248 PromotionPopup(hwndMain);
\r
5251 /* Toggle ShowThinking */
\r
5253 ToggleShowThinking()
\r
5255 appData.showThinking = !appData.showThinking;
\r
5256 ShowThinkingEvent();
\r
5260 LoadGameDialog(HWND hwnd, char* title)
\r
5264 char fileTitle[MSG_SIZ];
\r
5265 f = OpenFileDialog(hwnd, "rb", "",
\r
5266 appData.oldSaveStyle ? "gam" : "pgn",
\r
5268 title, &number, fileTitle, NULL);
\r
5270 cmailMsgLoaded = FALSE;
\r
5271 if (number == 0) {
\r
5272 int error = GameListBuild(f);
\r
5274 DisplayError("Cannot build game list", error);
\r
5275 } else if (!ListEmpty(&gameList) &&
\r
5276 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5277 GameListPopUp(f, fileTitle);
\r
5280 GameListDestroy();
\r
5283 LoadGame(f, number, fileTitle, FALSE);
\r
5287 int get_term_width()
\r
5292 HFONT hfont, hold_font;
\r
5297 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5301 // get the text metrics
\r
5302 hdc = GetDC(hText);
\r
5303 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5304 if (consoleCF.dwEffects & CFE_BOLD)
\r
5305 lf.lfWeight = FW_BOLD;
\r
5306 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5307 lf.lfItalic = TRUE;
\r
5308 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5309 lf.lfStrikeOut = TRUE;
\r
5310 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5311 lf.lfUnderline = TRUE;
\r
5312 hfont = CreateFontIndirect(&lf);
\r
5313 hold_font = SelectObject(hdc, hfont);
\r
5314 GetTextMetrics(hdc, &tm);
\r
5315 SelectObject(hdc, hold_font);
\r
5316 DeleteObject(hfont);
\r
5317 ReleaseDC(hText, hdc);
\r
5319 // get the rectangle
\r
5320 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5322 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5325 void UpdateICSWidth(HWND hText)
\r
5327 LONG old_width, new_width;
\r
5329 new_width = get_term_width(hText, FALSE);
\r
5330 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5331 if (new_width != old_width)
\r
5333 ics_update_width(new_width);
\r
5334 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5339 ChangedConsoleFont()
\r
5342 CHARRANGE tmpsel, sel;
\r
5343 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5344 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5345 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5348 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5349 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5350 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5351 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5352 * size. This was undocumented in the version of MSVC++ that I had
\r
5353 * when I wrote the code, but is apparently documented now.
\r
5355 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5356 cfmt.bCharSet = f->lf.lfCharSet;
\r
5357 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5358 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5359 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5360 /* Why are the following seemingly needed too? */
\r
5361 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5362 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5363 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5365 tmpsel.cpMax = -1; /*999999?*/
\r
5366 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5367 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5368 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5369 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5371 paraf.cbSize = sizeof(paraf);
\r
5372 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5373 paraf.dxStartIndent = 0;
\r
5374 paraf.dxOffset = WRAP_INDENT;
\r
5375 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5377 UpdateICSWidth(hText);
\r
5380 /*---------------------------------------------------------------------------*\
\r
5382 * Window Proc for main window
\r
5384 \*---------------------------------------------------------------------------*/
\r
5386 /* Process messages for main window, etc. */
\r
5388 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5391 int wmId, wmEvent;
\r
5395 char fileTitle[MSG_SIZ];
\r
5396 char buf[MSG_SIZ];
\r
5397 static SnapData sd;
\r
5399 switch (message) {
\r
5401 case WM_PAINT: /* message: repaint portion of window */
\r
5405 case WM_ERASEBKGND:
\r
5406 if (IsIconic(hwnd)) {
\r
5407 /* Cheat; change the message */
\r
5408 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5410 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5414 case WM_LBUTTONDOWN:
\r
5415 case WM_MBUTTONDOWN:
\r
5416 case WM_RBUTTONDOWN:
\r
5417 case WM_LBUTTONUP:
\r
5418 case WM_MBUTTONUP:
\r
5419 case WM_RBUTTONUP:
\r
5420 case WM_MOUSEMOVE:
\r
5421 case WM_MOUSEWHEEL:
\r
5422 MouseEvent(hwnd, message, wParam, lParam);
\r
5425 JAWS_KB_NAVIGATION
\r
5429 JAWS_ALT_INTERCEPT
\r
5431 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5432 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5433 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5434 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5436 SendMessage(h, message, wParam, lParam);
\r
5437 } else if(lParam != KF_REPEAT) {
\r
5438 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5439 PopUpMoveDialog((char)wParam);
\r
5440 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5441 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5446 case WM_PALETTECHANGED:
\r
5447 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5449 HDC hdc = GetDC(hwndMain);
\r
5450 SelectPalette(hdc, hPal, TRUE);
\r
5451 nnew = RealizePalette(hdc);
\r
5453 paletteChanged = TRUE;
\r
5454 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5456 ReleaseDC(hwnd, hdc);
\r
5460 case WM_QUERYNEWPALETTE:
\r
5461 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5463 HDC hdc = GetDC(hwndMain);
\r
5464 paletteChanged = FALSE;
\r
5465 SelectPalette(hdc, hPal, FALSE);
\r
5466 nnew = RealizePalette(hdc);
\r
5468 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5470 ReleaseDC(hwnd, hdc);
\r
5475 case WM_COMMAND: /* message: command from application menu */
\r
5476 wmId = LOWORD(wParam);
\r
5477 wmEvent = HIWORD(wParam);
\r
5482 SAY("new game enter a move to play against the computer with white");
\r
5485 case IDM_NewGameFRC:
\r
5486 if( NewGameFRC() == 0 ) {
\r
5491 case IDM_NewVariant:
\r
5492 NewVariantPopup(hwnd);
\r
5495 case IDM_LoadGame:
\r
5496 LoadGameDialog(hwnd, "Load Game from File");
\r
5499 case IDM_LoadNextGame:
\r
5503 case IDM_LoadPrevGame:
\r
5507 case IDM_ReloadGame:
\r
5511 case IDM_LoadPosition:
\r
5512 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5513 Reset(FALSE, TRUE);
\r
5516 f = OpenFileDialog(hwnd, "rb", "",
\r
5517 appData.oldSaveStyle ? "pos" : "fen",
\r
5519 "Load Position from File", &number, fileTitle, NULL);
\r
5521 LoadPosition(f, number, fileTitle);
\r
5525 case IDM_LoadNextPosition:
\r
5526 ReloadPosition(1);
\r
5529 case IDM_LoadPrevPosition:
\r
5530 ReloadPosition(-1);
\r
5533 case IDM_ReloadPosition:
\r
5534 ReloadPosition(0);
\r
5537 case IDM_SaveGame:
\r
5538 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5539 f = OpenFileDialog(hwnd, "a", defName,
\r
5540 appData.oldSaveStyle ? "gam" : "pgn",
\r
5542 "Save Game to File", NULL, fileTitle, NULL);
\r
5544 SaveGame(f, 0, "");
\r
5548 case IDM_SavePosition:
\r
5549 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5550 f = OpenFileDialog(hwnd, "a", defName,
\r
5551 appData.oldSaveStyle ? "pos" : "fen",
\r
5553 "Save Position to File", NULL, fileTitle, NULL);
\r
5555 SavePosition(f, 0, "");
\r
5559 case IDM_SaveDiagram:
\r
5560 defName = "diagram";
\r
5561 f = OpenFileDialog(hwnd, "wb", defName,
\r
5564 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5570 case IDM_CopyGame:
\r
5571 CopyGameToClipboard();
\r
5574 case IDM_PasteGame:
\r
5575 PasteGameFromClipboard();
\r
5578 case IDM_CopyGameListToClipboard:
\r
5579 CopyGameListToClipboard();
\r
5582 /* [AS] Autodetect FEN or PGN data */
\r
5583 case IDM_PasteAny:
\r
5584 PasteGameOrFENFromClipboard();
\r
5587 /* [AS] Move history */
\r
5588 case IDM_ShowMoveHistory:
\r
5589 if( MoveHistoryIsUp() ) {
\r
5590 MoveHistoryPopDown();
\r
5593 MoveHistoryPopUp();
\r
5597 /* [AS] Eval graph */
\r
5598 case IDM_ShowEvalGraph:
\r
5599 if( EvalGraphIsUp() ) {
\r
5600 EvalGraphPopDown();
\r
5604 SetFocus(hwndMain);
\r
5608 /* [AS] Engine output */
\r
5609 case IDM_ShowEngineOutput:
\r
5610 if( EngineOutputIsUp() ) {
\r
5611 EngineOutputPopDown();
\r
5614 EngineOutputPopUp();
\r
5618 /* [AS] User adjudication */
\r
5619 case IDM_UserAdjudication_White:
\r
5620 UserAdjudicationEvent( +1 );
\r
5623 case IDM_UserAdjudication_Black:
\r
5624 UserAdjudicationEvent( -1 );
\r
5627 case IDM_UserAdjudication_Draw:
\r
5628 UserAdjudicationEvent( 0 );
\r
5631 /* [AS] Game list options dialog */
\r
5632 case IDM_GameListOptions:
\r
5633 GameListOptions();
\r
5640 case IDM_CopyPosition:
\r
5641 CopyFENToClipboard();
\r
5644 case IDM_PastePosition:
\r
5645 PasteFENFromClipboard();
\r
5648 case IDM_MailMove:
\r
5652 case IDM_ReloadCMailMsg:
\r
5653 Reset(TRUE, TRUE);
\r
5654 ReloadCmailMsgEvent(FALSE);
\r
5657 case IDM_Minimize:
\r
5658 ShowWindow(hwnd, SW_MINIMIZE);
\r
5665 case IDM_MachineWhite:
\r
5666 MachineWhiteEvent();
\r
5668 * refresh the tags dialog only if it's visible
\r
5670 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5672 tags = PGNTags(&gameInfo);
\r
5673 TagsPopUp(tags, CmailMsg());
\r
5676 SAY("computer starts playing white");
\r
5679 case IDM_MachineBlack:
\r
5680 MachineBlackEvent();
\r
5682 * refresh the tags dialog only if it's visible
\r
5684 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5686 tags = PGNTags(&gameInfo);
\r
5687 TagsPopUp(tags, CmailMsg());
\r
5690 SAY("computer starts playing black");
\r
5693 case IDM_TwoMachines:
\r
5694 TwoMachinesEvent();
\r
5696 * refresh the tags dialog only if it's visible
\r
5698 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5700 tags = PGNTags(&gameInfo);
\r
5701 TagsPopUp(tags, CmailMsg());
\r
5704 SAY("programs start playing each other");
\r
5707 case IDM_AnalysisMode:
\r
5708 if (!first.analysisSupport) {
\r
5709 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5710 DisplayError(buf, 0);
\r
5712 SAY("analyzing current position");
\r
5713 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5714 if (appData.icsActive) {
\r
5715 if (gameMode != IcsObserving) {
\r
5716 sprintf(buf, "You are not observing a game");
\r
5717 DisplayError(buf, 0);
\r
5718 /* secure check */
\r
5719 if (appData.icsEngineAnalyze) {
\r
5720 if (appData.debugMode)
\r
5721 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5722 ExitAnalyzeMode();
\r
5728 /* if enable, user want disable icsEngineAnalyze */
\r
5729 if (appData.icsEngineAnalyze) {
\r
5730 ExitAnalyzeMode();
\r
5734 appData.icsEngineAnalyze = TRUE;
\r
5735 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5738 if (!appData.showThinking) ToggleShowThinking();
\r
5739 AnalyzeModeEvent();
\r
5743 case IDM_AnalyzeFile:
\r
5744 if (!first.analysisSupport) {
\r
5745 char buf[MSG_SIZ];
\r
5746 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5747 DisplayError(buf, 0);
\r
5749 if (!appData.showThinking) ToggleShowThinking();
\r
5750 AnalyzeFileEvent();
\r
5751 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5752 AnalysisPeriodicEvent(1);
\r
5756 case IDM_IcsClient:
\r
5760 case IDM_EditGame:
\r
5765 case IDM_EditPosition:
\r
5766 EditPositionEvent();
\r
5767 SAY("to set up a position type a FEN");
\r
5770 case IDM_Training:
\r
5774 case IDM_ShowGameList:
\r
5775 ShowGameListProc();
\r
5778 case IDM_EditTags:
\r
5782 case IDM_EditComment:
\r
5783 if (commentUp && editComment) {
\r
5786 EditCommentEvent();
\r
5806 case IDM_CallFlag:
\r
5826 case IDM_StopObserving:
\r
5827 StopObservingEvent();
\r
5830 case IDM_StopExamining:
\r
5831 StopExaminingEvent();
\r
5834 case IDM_TypeInMove:
\r
5835 PopUpMoveDialog('\000');
\r
5838 case IDM_TypeInName:
\r
5839 PopUpNameDialog('\000');
\r
5842 case IDM_Backward:
\r
5844 SetFocus(hwndMain);
\r
5851 SetFocus(hwndMain);
\r
5856 SetFocus(hwndMain);
\r
5861 SetFocus(hwndMain);
\r
5868 case IDM_TruncateGame:
\r
5869 TruncateGameEvent();
\r
5876 case IDM_RetractMove:
\r
5877 RetractMoveEvent();
\r
5880 case IDM_FlipView:
\r
5881 flipView = !flipView;
\r
5882 DrawPosition(FALSE, NULL);
\r
5885 case IDM_FlipClock:
\r
5886 flipClock = !flipClock;
\r
5887 DisplayBothClocks();
\r
5888 DrawPosition(FALSE, NULL);
\r
5891 case IDM_MuteSounds:
\r
5892 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5893 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5894 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5897 case IDM_GeneralOptions:
\r
5898 GeneralOptionsPopup(hwnd);
\r
5899 DrawPosition(TRUE, NULL);
\r
5902 case IDM_BoardOptions:
\r
5903 BoardOptionsPopup(hwnd);
\r
5906 case IDM_EnginePlayOptions:
\r
5907 EnginePlayOptionsPopup(hwnd);
\r
5910 case IDM_Engine1Options:
\r
5911 EngineOptionsPopup(hwnd, &first);
\r
5914 case IDM_Engine2Options:
\r
5915 EngineOptionsPopup(hwnd, &second);
\r
5918 case IDM_OptionsUCI:
\r
5919 UciOptionsPopup(hwnd);
\r
5922 case IDM_IcsOptions:
\r
5923 IcsOptionsPopup(hwnd);
\r
5927 FontsOptionsPopup(hwnd);
\r
5931 SoundOptionsPopup(hwnd);
\r
5934 case IDM_CommPort:
\r
5935 CommPortOptionsPopup(hwnd);
\r
5938 case IDM_LoadOptions:
\r
5939 LoadOptionsPopup(hwnd);
\r
5942 case IDM_SaveOptions:
\r
5943 SaveOptionsPopup(hwnd);
\r
5946 case IDM_TimeControl:
\r
5947 TimeControlOptionsPopup(hwnd);
\r
5950 case IDM_SaveSettings:
\r
5951 SaveSettings(settingsFileName);
\r
5954 case IDM_SaveSettingsOnExit:
\r
5955 saveSettingsOnExit = !saveSettingsOnExit;
\r
5956 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5957 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5958 MF_CHECKED : MF_UNCHECKED));
\r
5969 case IDM_AboutGame:
\r
5974 appData.debugMode = !appData.debugMode;
\r
5975 if (appData.debugMode) {
\r
5976 char dir[MSG_SIZ];
\r
5977 GetCurrentDirectory(MSG_SIZ, dir);
\r
5978 SetCurrentDirectory(installDir);
\r
5979 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5980 SetCurrentDirectory(dir);
\r
5981 setbuf(debugFP, NULL);
\r
5988 case IDM_HELPCONTENTS:
\r
5989 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5990 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5991 MessageBox (GetFocus(),
\r
5992 "Unable to activate help",
\r
5993 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5997 case IDM_HELPSEARCH:
\r
5998 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\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_HELPHELP:
\r
6007 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6008 MessageBox (GetFocus(),
\r
6009 "Unable to activate help",
\r
6010 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6015 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6017 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6018 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6019 FreeProcInstance(lpProc);
\r
6022 case IDM_DirectCommand1:
\r
6023 AskQuestionEvent("Direct Command",
\r
6024 "Send to chess program:", "", "1");
\r
6026 case IDM_DirectCommand2:
\r
6027 AskQuestionEvent("Direct Command",
\r
6028 "Send to second chess program:", "", "2");
\r
6031 case EP_WhitePawn:
\r
6032 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6033 fromX = fromY = -1;
\r
6036 case EP_WhiteKnight:
\r
6037 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6038 fromX = fromY = -1;
\r
6041 case EP_WhiteBishop:
\r
6042 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6043 fromX = fromY = -1;
\r
6046 case EP_WhiteRook:
\r
6047 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6048 fromX = fromY = -1;
\r
6051 case EP_WhiteQueen:
\r
6052 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6053 fromX = fromY = -1;
\r
6056 case EP_WhiteFerz:
\r
6057 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6058 fromX = fromY = -1;
\r
6061 case EP_WhiteWazir:
\r
6062 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6063 fromX = fromY = -1;
\r
6066 case EP_WhiteAlfil:
\r
6067 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6068 fromX = fromY = -1;
\r
6071 case EP_WhiteCannon:
\r
6072 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6073 fromX = fromY = -1;
\r
6076 case EP_WhiteCardinal:
\r
6077 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6078 fromX = fromY = -1;
\r
6081 case EP_WhiteMarshall:
\r
6082 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6083 fromX = fromY = -1;
\r
6086 case EP_WhiteKing:
\r
6087 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6088 fromX = fromY = -1;
\r
6091 case EP_BlackPawn:
\r
6092 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6093 fromX = fromY = -1;
\r
6096 case EP_BlackKnight:
\r
6097 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6098 fromX = fromY = -1;
\r
6101 case EP_BlackBishop:
\r
6102 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6103 fromX = fromY = -1;
\r
6106 case EP_BlackRook:
\r
6107 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6108 fromX = fromY = -1;
\r
6111 case EP_BlackQueen:
\r
6112 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6113 fromX = fromY = -1;
\r
6116 case EP_BlackFerz:
\r
6117 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6118 fromX = fromY = -1;
\r
6121 case EP_BlackWazir:
\r
6122 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6123 fromX = fromY = -1;
\r
6126 case EP_BlackAlfil:
\r
6127 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6128 fromX = fromY = -1;
\r
6131 case EP_BlackCannon:
\r
6132 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6133 fromX = fromY = -1;
\r
6136 case EP_BlackCardinal:
\r
6137 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6138 fromX = fromY = -1;
\r
6141 case EP_BlackMarshall:
\r
6142 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6143 fromX = fromY = -1;
\r
6146 case EP_BlackKing:
\r
6147 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6148 fromX = fromY = -1;
\r
6151 case EP_EmptySquare:
\r
6152 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6153 fromX = fromY = -1;
\r
6156 case EP_ClearBoard:
\r
6157 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6158 fromX = fromY = -1;
\r
6162 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6163 fromX = fromY = -1;
\r
6167 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6168 fromX = fromY = -1;
\r
6172 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6173 fromX = fromY = -1;
\r
6177 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6178 fromX = fromY = -1;
\r
6182 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6183 fromX = fromY = -1;
\r
6187 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6188 fromX = fromY = -1;
\r
6192 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6193 fromX = fromY = -1;
\r
6197 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6198 fromX = fromY = -1;
\r
6202 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6203 fromX = fromY = -1;
\r
6207 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6213 case CLOCK_TIMER_ID:
\r
6214 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6215 clockTimerEvent = 0;
\r
6216 DecrementClocks(); /* call into back end */
\r
6218 case LOAD_GAME_TIMER_ID:
\r
6219 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6220 loadGameTimerEvent = 0;
\r
6221 AutoPlayGameLoop(); /* call into back end */
\r
6223 case ANALYSIS_TIMER_ID:
\r
6224 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6225 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6226 AnalysisPeriodicEvent(0);
\r
6228 KillTimer(hwnd, analysisTimerEvent);
\r
6229 analysisTimerEvent = 0;
\r
6232 case DELAYED_TIMER_ID:
\r
6233 KillTimer(hwnd, delayedTimerEvent);
\r
6234 delayedTimerEvent = 0;
\r
6235 delayedTimerCallback();
\r
6240 case WM_USER_Input:
\r
6241 InputEvent(hwnd, message, wParam, lParam);
\r
6244 /* [AS] Also move "attached" child windows */
\r
6245 case WM_WINDOWPOSCHANGING:
\r
6247 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6248 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6250 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6251 /* Window is moving */
\r
6254 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6255 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6256 rcMain.right = boardX + winWidth;
\r
6257 rcMain.top = boardY;
\r
6258 rcMain.bottom = boardY + winHeight;
\r
6260 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6261 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6262 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6263 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6264 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6271 /* [AS] Snapping */
\r
6272 case WM_ENTERSIZEMOVE:
\r
6273 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6274 if (hwnd == hwndMain) {
\r
6275 doingSizing = TRUE;
\r
6278 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6282 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6283 if (hwnd == hwndMain) {
\r
6284 lastSizing = wParam;
\r
6289 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6290 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6292 case WM_EXITSIZEMOVE:
\r
6293 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6294 if (hwnd == hwndMain) {
\r
6296 doingSizing = FALSE;
\r
6297 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6298 GetClientRect(hwnd, &client);
\r
6299 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6301 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6303 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6306 case WM_DESTROY: /* message: window being destroyed */
\r
6307 PostQuitMessage(0);
\r
6311 if (hwnd == hwndMain) {
\r
6316 default: /* Passes it on if unprocessed */
\r
6317 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6322 /*---------------------------------------------------------------------------*\
\r
6324 * Misc utility routines
\r
6326 \*---------------------------------------------------------------------------*/
\r
6329 * Decent random number generator, at least not as bad as Windows
\r
6330 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6332 unsigned int randstate;
\r
6337 randstate = randstate * 1664525 + 1013904223;
\r
6338 return (int) randstate & 0x7fffffff;
\r
6342 mysrandom(unsigned int seed)
\r
6349 * returns TRUE if user selects a different color, FALSE otherwise
\r
6353 ChangeColor(HWND hwnd, COLORREF *which)
\r
6355 static BOOL firstTime = TRUE;
\r
6356 static DWORD customColors[16];
\r
6358 COLORREF newcolor;
\r
6363 /* Make initial colors in use available as custom colors */
\r
6364 /* Should we put the compiled-in defaults here instead? */
\r
6366 customColors[i++] = lightSquareColor & 0xffffff;
\r
6367 customColors[i++] = darkSquareColor & 0xffffff;
\r
6368 customColors[i++] = whitePieceColor & 0xffffff;
\r
6369 customColors[i++] = blackPieceColor & 0xffffff;
\r
6370 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6371 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6373 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6374 customColors[i++] = textAttribs[ccl].color;
\r
6376 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6377 firstTime = FALSE;
\r
6380 cc.lStructSize = sizeof(cc);
\r
6381 cc.hwndOwner = hwnd;
\r
6382 cc.hInstance = NULL;
\r
6383 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6384 cc.lpCustColors = (LPDWORD) customColors;
\r
6385 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6387 if (!ChooseColor(&cc)) return FALSE;
\r
6389 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6390 if (newcolor == *which) return FALSE;
\r
6391 *which = newcolor;
\r
6395 InitDrawingColors();
\r
6396 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6401 MyLoadSound(MySound *ms)
\r
6407 if (ms->data) free(ms->data);
\r
6410 switch (ms->name[0]) {
\r
6416 /* System sound from Control Panel. Don't preload here. */
\r
6420 if (ms->name[1] == NULLCHAR) {
\r
6421 /* "!" alone = silence */
\r
6424 /* Builtin wave resource. Error if not found. */
\r
6425 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6426 if (h == NULL) break;
\r
6427 ms->data = (void *)LoadResource(hInst, h);
\r
6428 if (h == NULL) break;
\r
6433 /* .wav file. Error if not found. */
\r
6434 f = fopen(ms->name, "rb");
\r
6435 if (f == NULL) break;
\r
6436 if (fstat(fileno(f), &st) < 0) break;
\r
6437 ms->data = malloc(st.st_size);
\r
6438 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6444 char buf[MSG_SIZ];
\r
6445 sprintf(buf, "Error loading sound %s", ms->name);
\r
6446 DisplayError(buf, GetLastError());
\r
6452 MyPlaySound(MySound *ms)
\r
6454 BOOLEAN ok = FALSE;
\r
6456 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6457 switch (ms->name[0]) {
\r
6459 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6464 /* System sound from Control Panel (deprecated feature).
\r
6465 "$" alone or an unset sound name gets default beep (still in use). */
\r
6466 if (ms->name[1]) {
\r
6467 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6469 if (!ok) ok = MessageBeep(MB_OK);
\r
6472 /* Builtin wave resource, or "!" alone for silence */
\r
6473 if (ms->name[1]) {
\r
6474 if (ms->data == NULL) return FALSE;
\r
6475 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6481 /* .wav file. Error if not found. */
\r
6482 if (ms->data == NULL) return FALSE;
\r
6483 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6486 /* Don't print an error: this can happen innocently if the sound driver
\r
6487 is busy; for instance, if another instance of WinBoard is playing
\r
6488 a sound at about the same time. */
\r
6494 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6497 OPENFILENAME *ofn;
\r
6498 static UINT *number; /* gross that this is static */
\r
6500 switch (message) {
\r
6501 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6502 /* Center the dialog over the application window */
\r
6503 ofn = (OPENFILENAME *) lParam;
\r
6504 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6505 number = (UINT *) ofn->lCustData;
\r
6506 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6510 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6511 return FALSE; /* Allow for further processing */
\r
6514 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6515 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6517 return FALSE; /* Allow for further processing */
\r
6523 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6525 static UINT *number;
\r
6526 OPENFILENAME *ofname;
\r
6529 case WM_INITDIALOG:
\r
6530 ofname = (OPENFILENAME *)lParam;
\r
6531 number = (UINT *)(ofname->lCustData);
\r
6534 ofnot = (OFNOTIFY *)lParam;
\r
6535 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6536 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6545 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6546 char *nameFilt, char *dlgTitle, UINT *number,
\r
6547 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6549 OPENFILENAME openFileName;
\r
6550 char buf1[MSG_SIZ];
\r
6553 if (fileName == NULL) fileName = buf1;
\r
6554 if (defName == NULL) {
\r
6555 strcpy(fileName, "*.");
\r
6556 strcat(fileName, defExt);
\r
6558 strcpy(fileName, defName);
\r
6560 if (fileTitle) strcpy(fileTitle, "");
\r
6561 if (number) *number = 0;
\r
6563 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6564 openFileName.hwndOwner = hwnd;
\r
6565 openFileName.hInstance = (HANDLE) hInst;
\r
6566 openFileName.lpstrFilter = nameFilt;
\r
6567 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6568 openFileName.nMaxCustFilter = 0L;
\r
6569 openFileName.nFilterIndex = 1L;
\r
6570 openFileName.lpstrFile = fileName;
\r
6571 openFileName.nMaxFile = MSG_SIZ;
\r
6572 openFileName.lpstrFileTitle = fileTitle;
\r
6573 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6574 openFileName.lpstrInitialDir = NULL;
\r
6575 openFileName.lpstrTitle = dlgTitle;
\r
6576 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6577 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6578 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6579 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6580 openFileName.nFileOffset = 0;
\r
6581 openFileName.nFileExtension = 0;
\r
6582 openFileName.lpstrDefExt = defExt;
\r
6583 openFileName.lCustData = (LONG) number;
\r
6584 openFileName.lpfnHook = oldDialog ?
\r
6585 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6586 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6588 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6589 GetOpenFileName(&openFileName)) {
\r
6590 /* open the file */
\r
6591 f = fopen(openFileName.lpstrFile, write);
\r
6593 MessageBox(hwnd, "File open failed", NULL,
\r
6594 MB_OK|MB_ICONEXCLAMATION);
\r
6598 int err = CommDlgExtendedError();
\r
6599 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6608 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6610 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6613 * Get the first pop-up menu in the menu template. This is the
\r
6614 * menu that TrackPopupMenu displays.
\r
6616 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6618 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6621 * TrackPopup uses screen coordinates, so convert the
\r
6622 * coordinates of the mouse click to screen coordinates.
\r
6624 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6626 /* Draw and track the floating pop-up menu. */
\r
6627 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6628 pt.x, pt.y, 0, hwnd, NULL);
\r
6630 /* Destroy the menu.*/
\r
6631 DestroyMenu(hmenu);
\r
6636 int sizeX, sizeY, newSizeX, newSizeY;
\r
6638 } ResizeEditPlusButtonsClosure;
\r
6641 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6643 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6647 if (hChild == cl->hText) return TRUE;
\r
6648 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6649 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6650 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6651 ScreenToClient(cl->hDlg, &pt);
\r
6652 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6653 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6657 /* Resize a dialog that has a (rich) edit field filling most of
\r
6658 the top, with a row of buttons below */
\r
6660 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6663 int newTextHeight, newTextWidth;
\r
6664 ResizeEditPlusButtonsClosure cl;
\r
6666 /*if (IsIconic(hDlg)) return;*/
\r
6667 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6669 cl.hdwp = BeginDeferWindowPos(8);
\r
6671 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6672 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6673 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6674 if (newTextHeight < 0) {
\r
6675 newSizeY += -newTextHeight;
\r
6676 newTextHeight = 0;
\r
6678 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6679 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6685 cl.newSizeX = newSizeX;
\r
6686 cl.newSizeY = newSizeY;
\r
6687 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6689 EndDeferWindowPos(cl.hdwp);
\r
6692 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6694 RECT rChild, rParent;
\r
6695 int wChild, hChild, wParent, hParent;
\r
6696 int wScreen, hScreen, xNew, yNew;
\r
6699 /* Get the Height and Width of the child window */
\r
6700 GetWindowRect (hwndChild, &rChild);
\r
6701 wChild = rChild.right - rChild.left;
\r
6702 hChild = rChild.bottom - rChild.top;
\r
6704 /* Get the Height and Width of the parent window */
\r
6705 GetWindowRect (hwndParent, &rParent);
\r
6706 wParent = rParent.right - rParent.left;
\r
6707 hParent = rParent.bottom - rParent.top;
\r
6709 /* Get the display limits */
\r
6710 hdc = GetDC (hwndChild);
\r
6711 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6712 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6713 ReleaseDC(hwndChild, hdc);
\r
6715 /* Calculate new X position, then adjust for screen */
\r
6716 xNew = rParent.left + ((wParent - wChild) /2);
\r
6719 } else if ((xNew+wChild) > wScreen) {
\r
6720 xNew = wScreen - wChild;
\r
6723 /* Calculate new Y position, then adjust for screen */
\r
6725 yNew = rParent.top + ((hParent - hChild) /2);
\r
6728 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6733 } else if ((yNew+hChild) > hScreen) {
\r
6734 yNew = hScreen - hChild;
\r
6737 /* Set it, and return */
\r
6738 return SetWindowPos (hwndChild, NULL,
\r
6739 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6742 /* Center one window over another */
\r
6743 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6745 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6748 /*---------------------------------------------------------------------------*\
\r
6750 * Startup Dialog functions
\r
6752 \*---------------------------------------------------------------------------*/
\r
6754 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6756 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6758 while (*cd != NULL) {
\r
6759 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6765 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6767 char buf1[ARG_MAX];
\r
6770 if (str[0] == '@') {
\r
6771 FILE* f = fopen(str + 1, "r");
\r
6773 DisplayFatalError(str + 1, errno, 2);
\r
6776 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6778 buf1[len] = NULLCHAR;
\r
6782 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6785 char buf[MSG_SIZ];
\r
6786 char *end = strchr(str, '\n');
\r
6787 if (end == NULL) return;
\r
6788 memcpy(buf, str, end - str);
\r
6789 buf[end - str] = NULLCHAR;
\r
6790 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6796 SetStartupDialogEnables(HWND hDlg)
\r
6798 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6799 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6800 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6801 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6802 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6803 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6804 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6805 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6806 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6807 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6808 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6809 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6810 IsDlgButtonChecked(hDlg, OPT_View));
\r
6814 QuoteForFilename(char *filename)
\r
6816 int dquote, space;
\r
6817 dquote = strchr(filename, '"') != NULL;
\r
6818 space = strchr(filename, ' ') != NULL;
\r
6819 if (dquote || space) {
\r
6831 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6833 char buf[MSG_SIZ];
\r
6836 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6837 q = QuoteForFilename(nthcp);
\r
6838 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6839 if (*nthdir != NULLCHAR) {
\r
6840 q = QuoteForFilename(nthdir);
\r
6841 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6843 if (*nthcp == NULLCHAR) {
\r
6844 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6845 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6846 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6847 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6852 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6854 char buf[MSG_SIZ];
\r
6858 switch (message) {
\r
6859 case WM_INITDIALOG:
\r
6860 /* Center the dialog */
\r
6861 CenterWindow (hDlg, GetDesktopWindow());
\r
6862 /* Initialize the dialog items */
\r
6863 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6864 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6865 firstChessProgramNames);
\r
6866 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6867 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6868 secondChessProgramNames);
\r
6869 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6870 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6871 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6872 if (*appData.icsHelper != NULLCHAR) {
\r
6873 char *q = QuoteForFilename(appData.icsHelper);
\r
6874 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6876 if (*appData.icsHost == NULLCHAR) {
\r
6877 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6878 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6879 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6880 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6881 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6884 if (appData.icsActive) {
\r
6885 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6887 else if (appData.noChessProgram) {
\r
6888 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6891 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6894 SetStartupDialogEnables(hDlg);
\r
6898 switch (LOWORD(wParam)) {
\r
6900 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6901 strcpy(buf, "/fcp=");
\r
6902 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6904 ParseArgs(StringGet, &p);
\r
6905 strcpy(buf, "/scp=");
\r
6906 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6908 ParseArgs(StringGet, &p);
\r
6909 appData.noChessProgram = FALSE;
\r
6910 appData.icsActive = FALSE;
\r
6911 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6912 strcpy(buf, "/ics /icshost=");
\r
6913 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6915 ParseArgs(StringGet, &p);
\r
6916 if (appData.zippyPlay) {
\r
6917 strcpy(buf, "/fcp=");
\r
6918 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6920 ParseArgs(StringGet, &p);
\r
6922 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6923 appData.noChessProgram = TRUE;
\r
6924 appData.icsActive = FALSE;
\r
6926 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6927 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6930 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6931 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6933 ParseArgs(StringGet, &p);
\r
6935 EndDialog(hDlg, TRUE);
\r
6942 case IDM_HELPCONTENTS:
\r
6943 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6944 MessageBox (GetFocus(),
\r
6945 "Unable to activate help",
\r
6946 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6951 SetStartupDialogEnables(hDlg);
\r
6959 /*---------------------------------------------------------------------------*\
\r
6961 * About box dialog functions
\r
6963 \*---------------------------------------------------------------------------*/
\r
6965 /* Process messages for "About" dialog box */
\r
6967 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6969 switch (message) {
\r
6970 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6971 /* Center the dialog over the application window */
\r
6972 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6973 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6977 case WM_COMMAND: /* message: received a command */
\r
6978 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6979 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6980 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6988 /*---------------------------------------------------------------------------*\
\r
6990 * Comment Dialog functions
\r
6992 \*---------------------------------------------------------------------------*/
\r
6995 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6997 static HANDLE hwndText = NULL;
\r
6998 int len, newSizeX, newSizeY, flags;
\r
6999 static int sizeX, sizeY;
\r
7004 switch (message) {
\r
7005 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7006 /* Initialize the dialog items */
\r
7007 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7008 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7009 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7010 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7011 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7012 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7013 SetWindowText(hDlg, commentTitle);
\r
7014 if (editComment) {
\r
7015 SetFocus(hwndText);
\r
7017 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7019 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7020 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7021 MAKELPARAM(FALSE, 0));
\r
7022 /* Size and position the dialog */
\r
7023 if (!commentDialog) {
\r
7024 commentDialog = hDlg;
\r
7025 flags = SWP_NOZORDER;
\r
7026 GetClientRect(hDlg, &rect);
\r
7027 sizeX = rect.right;
\r
7028 sizeY = rect.bottom;
\r
7029 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7030 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7031 WINDOWPLACEMENT wp;
\r
7032 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7033 wp.length = sizeof(WINDOWPLACEMENT);
\r
7035 wp.showCmd = SW_SHOW;
\r
7036 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7037 wp.rcNormalPosition.left = commentX;
\r
7038 wp.rcNormalPosition.right = commentX + commentW;
\r
7039 wp.rcNormalPosition.top = commentY;
\r
7040 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7041 SetWindowPlacement(hDlg, &wp);
\r
7043 GetClientRect(hDlg, &rect);
\r
7044 newSizeX = rect.right;
\r
7045 newSizeY = rect.bottom;
\r
7046 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7047 newSizeX, newSizeY);
\r
7054 case WM_COMMAND: /* message: received a command */
\r
7055 switch (LOWORD(wParam)) {
\r
7057 if (editComment) {
\r
7059 /* Read changed options from the dialog box */
\r
7060 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7061 len = GetWindowTextLength(hwndText);
\r
7062 str = (char *) malloc(len + 1);
\r
7063 GetWindowText(hwndText, str, len + 1);
\r
7072 ReplaceComment(commentIndex, str);
\r
7079 case OPT_CancelComment:
\r
7083 case OPT_ClearComment:
\r
7084 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7087 case OPT_EditComment:
\r
7088 EditCommentEvent();
\r
7097 newSizeX = LOWORD(lParam);
\r
7098 newSizeY = HIWORD(lParam);
\r
7099 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7104 case WM_GETMINMAXINFO:
\r
7105 /* Prevent resizing window too small */
\r
7106 mmi = (MINMAXINFO *) lParam;
\r
7107 mmi->ptMinTrackSize.x = 100;
\r
7108 mmi->ptMinTrackSize.y = 100;
\r
7115 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7120 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7122 if (str == NULL) str = "";
\r
7123 p = (char *) malloc(2 * strlen(str) + 2);
\r
7126 if (*str == '\n') *q++ = '\r';
\r
7130 if (commentText != NULL) free(commentText);
\r
7132 commentIndex = index;
\r
7133 commentTitle = title;
\r
7135 editComment = edit;
\r
7137 if (commentDialog) {
\r
7138 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7139 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
7141 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7142 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7143 hwndMain, (DLGPROC)lpProc);
\r
7144 FreeProcInstance(lpProc);
\r
7150 /*---------------------------------------------------------------------------*\
\r
7152 * Type-in move dialog functions
\r
7154 \*---------------------------------------------------------------------------*/
\r
7157 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7159 char move[MSG_SIZ];
\r
7161 ChessMove moveType;
\r
7162 int fromX, fromY, toX, toY;
\r
7165 switch (message) {
\r
7166 case WM_INITDIALOG:
\r
7167 move[0] = (char) lParam;
\r
7168 move[1] = NULLCHAR;
\r
7169 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7170 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7171 SetWindowText(hInput, move);
\r
7173 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7177 switch (LOWORD(wParam)) {
\r
7179 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7180 { int n; Board board;
\r
7182 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7183 EditPositionPasteFEN(move);
\r
7184 EndDialog(hDlg, TRUE);
\r
7187 // [HGM] movenum: allow move number to be typed in any mode
\r
7188 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7190 EndDialog(hDlg, TRUE);
\r
7194 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7195 gameMode != Training) {
\r
7196 DisplayMoveError("Displayed move is not current");
\r
7198 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7199 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7200 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7201 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7202 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7203 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7204 if (gameMode != Training)
\r
7205 forwardMostMove = currentMove;
\r
7206 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7208 DisplayMoveError("Could not parse move");
\r
7211 EndDialog(hDlg, TRUE);
\r
7214 EndDialog(hDlg, FALSE);
\r
7225 PopUpMoveDialog(char firstchar)
\r
7229 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7230 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7231 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7232 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7233 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7234 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7235 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7236 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7237 gameMode == Training) {
\r
7238 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7239 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7240 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7241 FreeProcInstance(lpProc);
\r
7245 /*---------------------------------------------------------------------------*\
\r
7247 * Type-in name dialog functions
\r
7249 \*---------------------------------------------------------------------------*/
\r
7252 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7254 char move[MSG_SIZ];
\r
7257 switch (message) {
\r
7258 case WM_INITDIALOG:
\r
7259 move[0] = (char) lParam;
\r
7260 move[1] = NULLCHAR;
\r
7261 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7262 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7263 SetWindowText(hInput, move);
\r
7265 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7269 switch (LOWORD(wParam)) {
\r
7271 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7272 appData.userName = strdup(move);
\r
7275 EndDialog(hDlg, TRUE);
\r
7278 EndDialog(hDlg, FALSE);
\r
7289 PopUpNameDialog(char firstchar)
\r
7293 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7294 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7295 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7296 FreeProcInstance(lpProc);
\r
7299 /*---------------------------------------------------------------------------*\
\r
7303 \*---------------------------------------------------------------------------*/
\r
7305 /* Nonmodal error box */
\r
7306 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7307 WPARAM wParam, LPARAM lParam);
\r
7310 ErrorPopUp(char *title, char *content)
\r
7314 BOOLEAN modal = hwndMain == NULL;
\r
7332 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7333 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7336 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7338 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7339 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7340 hwndMain, (DLGPROC)lpProc);
\r
7341 FreeProcInstance(lpProc);
\r
7348 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7349 if (errorDialog == NULL) return;
\r
7350 DestroyWindow(errorDialog);
\r
7351 errorDialog = NULL;
\r
7355 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7360 switch (message) {
\r
7361 case WM_INITDIALOG:
\r
7362 GetWindowRect(hDlg, &rChild);
\r
7365 SetWindowPos(hDlg, NULL, rChild.left,
\r
7366 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7367 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7371 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7372 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7373 and it doesn't work when you resize the dialog.
\r
7374 For now, just give it a default position.
\r
7376 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7378 errorDialog = hDlg;
\r
7379 SetWindowText(hDlg, errorTitle);
\r
7380 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7381 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7385 switch (LOWORD(wParam)) {
\r
7388 if (errorDialog == hDlg) errorDialog = NULL;
\r
7389 DestroyWindow(hDlg);
\r
7401 HWND gothicDialog = NULL;
\r
7404 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7408 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7410 switch (message) {
\r
7411 case WM_INITDIALOG:
\r
7412 GetWindowRect(hDlg, &rChild);
\r
7414 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7418 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7419 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7420 and it doesn't work when you resize the dialog.
\r
7421 For now, just give it a default position.
\r
7423 gothicDialog = hDlg;
\r
7424 SetWindowText(hDlg, errorTitle);
\r
7425 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7426 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7430 switch (LOWORD(wParam)) {
\r
7433 if (errorDialog == hDlg) errorDialog = NULL;
\r
7434 DestroyWindow(hDlg);
\r
7446 GothicPopUp(char *title, VariantClass variant)
\r
7449 static char *lastTitle;
\r
7451 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7452 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7454 if(lastTitle != title && gothicDialog != NULL) {
\r
7455 DestroyWindow(gothicDialog);
\r
7456 gothicDialog = NULL;
\r
7458 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7459 title = lastTitle;
\r
7460 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7461 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7462 hwndMain, (DLGPROC)lpProc);
\r
7463 FreeProcInstance(lpProc);
\r
7468 /*---------------------------------------------------------------------------*\
\r
7470 * Ics Interaction console functions
\r
7472 \*---------------------------------------------------------------------------*/
\r
7474 #define HISTORY_SIZE 64
\r
7475 static char *history[HISTORY_SIZE];
\r
7476 int histIn = 0, histP = 0;
\r
7479 SaveInHistory(char *cmd)
\r
7481 if (history[histIn] != NULL) {
\r
7482 free(history[histIn]);
\r
7483 history[histIn] = NULL;
\r
7485 if (*cmd == NULLCHAR) return;
\r
7486 history[histIn] = StrSave(cmd);
\r
7487 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7488 if (history[histIn] != NULL) {
\r
7489 free(history[histIn]);
\r
7490 history[histIn] = NULL;
\r
7496 PrevInHistory(char *cmd)
\r
7499 if (histP == histIn) {
\r
7500 if (history[histIn] != NULL) free(history[histIn]);
\r
7501 history[histIn] = StrSave(cmd);
\r
7503 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7504 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7506 return history[histP];
\r
7512 if (histP == histIn) return NULL;
\r
7513 histP = (histP + 1) % HISTORY_SIZE;
\r
7514 return history[histP];
\r
7521 BOOLEAN immediate;
\r
7522 } IcsTextMenuEntry;
\r
7523 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7524 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7527 ParseIcsTextMenu(char *icsTextMenuString)
\r
7530 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7531 char *p = icsTextMenuString;
\r
7532 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7535 if (e->command != NULL) {
\r
7537 e->command = NULL;
\r
7541 e = icsTextMenuEntry;
\r
7542 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7543 if (*p == ';' || *p == '\n') {
\r
7544 e->item = strdup("-");
\r
7545 e->command = NULL;
\r
7547 } else if (*p == '-') {
\r
7548 e->item = strdup("-");
\r
7549 e->command = NULL;
\r
7553 char *q, *r, *s, *t;
\r
7555 q = strchr(p, ',');
\r
7556 if (q == NULL) break;
\r
7558 r = strchr(q + 1, ',');
\r
7559 if (r == NULL) break;
\r
7561 s = strchr(r + 1, ',');
\r
7562 if (s == NULL) break;
\r
7565 t = strchr(s + 1, c);
\r
7568 t = strchr(s + 1, c);
\r
7570 if (t != NULL) *t = NULLCHAR;
\r
7571 e->item = strdup(p);
\r
7572 e->command = strdup(q + 1);
\r
7573 e->getname = *(r + 1) != '0';
\r
7574 e->immediate = *(s + 1) != '0';
\r
7578 if (t == NULL) break;
\r
7587 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7591 hmenu = LoadMenu(hInst, "TextMenu");
\r
7592 h = GetSubMenu(hmenu, 0);
\r
7594 if (strcmp(e->item, "-") == 0) {
\r
7595 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7597 if (e->item[0] == '|') {
\r
7598 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7599 IDM_CommandX + i, &e->item[1]);
\r
7601 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7610 WNDPROC consoleTextWindowProc;
\r
7613 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7615 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7616 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7620 SetWindowText(hInput, command);
\r
7622 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7624 sel.cpMin = 999999;
\r
7625 sel.cpMax = 999999;
\r
7626 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7631 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7632 if (sel.cpMin == sel.cpMax) {
\r
7633 /* Expand to surrounding word */
\r
7636 tr.chrg.cpMax = sel.cpMin;
\r
7637 tr.chrg.cpMin = --sel.cpMin;
\r
7638 if (sel.cpMin < 0) break;
\r
7639 tr.lpstrText = name;
\r
7640 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7641 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7645 tr.chrg.cpMin = sel.cpMax;
\r
7646 tr.chrg.cpMax = ++sel.cpMax;
\r
7647 tr.lpstrText = name;
\r
7648 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7649 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7652 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7653 MessageBeep(MB_ICONEXCLAMATION);
\r
7657 tr.lpstrText = name;
\r
7658 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7660 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7661 MessageBeep(MB_ICONEXCLAMATION);
\r
7664 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7667 sprintf(buf, "%s %s", command, name);
\r
7668 SetWindowText(hInput, buf);
\r
7669 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7671 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7672 SetWindowText(hInput, buf);
\r
7673 sel.cpMin = 999999;
\r
7674 sel.cpMax = 999999;
\r
7675 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7681 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7686 switch (message) {
\r
7688 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7691 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7694 sel.cpMin = 999999;
\r
7695 sel.cpMax = 999999;
\r
7696 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7697 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7702 if(wParam != '\022') {
\r
7703 if (wParam == '\t') {
\r
7704 if (GetKeyState(VK_SHIFT) < 0) {
\r
7706 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7707 if (buttonDesc[0].hwnd) {
\r
7708 SetFocus(buttonDesc[0].hwnd);
\r
7710 SetFocus(hwndMain);
\r
7714 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7717 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7718 JAWS_DELETE( SetFocus(hInput); )
\r
7719 SendMessage(hInput, message, wParam, lParam);
\r
7722 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7723 case WM_RBUTTONUP:
\r
7724 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7725 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7726 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7729 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7730 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7731 if (sel.cpMin == sel.cpMax) {
\r
7732 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7733 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7735 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7736 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7738 pt.x = LOWORD(lParam);
\r
7739 pt.y = HIWORD(lParam);
\r
7740 MenuPopup(hwnd, pt, hmenu, -1);
\r
7744 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7746 return SendMessage(hInput, message, wParam, lParam);
\r
7747 case WM_MBUTTONDOWN:
\r
7748 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7749 case WM_RBUTTONDOWN:
\r
7750 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7751 /* Move selection here if it was empty */
\r
7753 pt.x = LOWORD(lParam);
\r
7754 pt.y = HIWORD(lParam);
\r
7755 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7756 if (sel.cpMin == sel.cpMax) {
\r
7757 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7758 sel.cpMax = sel.cpMin;
\r
7759 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7761 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7765 switch (LOWORD(wParam)) {
\r
7766 case IDM_QuickPaste:
\r
7768 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7769 if (sel.cpMin == sel.cpMax) {
\r
7770 MessageBeep(MB_ICONEXCLAMATION);
\r
7773 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7774 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7775 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7780 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7783 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7786 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7790 int i = LOWORD(wParam) - IDM_CommandX;
\r
7791 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7792 icsTextMenuEntry[i].command != NULL) {
\r
7793 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7794 icsTextMenuEntry[i].getname,
\r
7795 icsTextMenuEntry[i].immediate);
\r
7803 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7806 WNDPROC consoleInputWindowProc;
\r
7809 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7811 char buf[MSG_SIZ];
\r
7813 static BOOL sendNextChar = FALSE;
\r
7814 static BOOL quoteNextChar = FALSE;
\r
7815 InputSource *is = consoleInputSource;
\r
7819 switch (message) {
\r
7821 if (!appData.localLineEditing || sendNextChar) {
\r
7822 is->buf[0] = (CHAR) wParam;
\r
7824 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7825 sendNextChar = FALSE;
\r
7828 if (quoteNextChar) {
\r
7829 buf[0] = (char) wParam;
\r
7830 buf[1] = NULLCHAR;
\r
7831 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7832 quoteNextChar = FALSE;
\r
7836 case '\r': /* Enter key */
\r
7837 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7838 if (consoleEcho) SaveInHistory(is->buf);
\r
7839 is->buf[is->count++] = '\n';
\r
7840 is->buf[is->count] = NULLCHAR;
\r
7841 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7842 if (consoleEcho) {
\r
7843 ConsoleOutput(is->buf, is->count, TRUE);
\r
7844 } else if (appData.localLineEditing) {
\r
7845 ConsoleOutput("\n", 1, TRUE);
\r
7848 case '\033': /* Escape key */
\r
7849 SetWindowText(hwnd, "");
\r
7850 cf.cbSize = sizeof(CHARFORMAT);
\r
7851 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7852 if (consoleEcho) {
\r
7853 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7855 cf.crTextColor = COLOR_ECHOOFF;
\r
7857 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7858 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7860 case '\t': /* Tab key */
\r
7861 if (GetKeyState(VK_SHIFT) < 0) {
\r
7863 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7866 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7867 if (buttonDesc[0].hwnd) {
\r
7868 SetFocus(buttonDesc[0].hwnd);
\r
7870 SetFocus(hwndMain);
\r
7874 case '\023': /* Ctrl+S */
\r
7875 sendNextChar = TRUE;
\r
7877 case '\021': /* Ctrl+Q */
\r
7878 quoteNextChar = TRUE;
\r
7888 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7889 p = PrevInHistory(buf);
\r
7891 SetWindowText(hwnd, p);
\r
7892 sel.cpMin = 999999;
\r
7893 sel.cpMax = 999999;
\r
7894 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7899 p = NextInHistory();
\r
7901 SetWindowText(hwnd, p);
\r
7902 sel.cpMin = 999999;
\r
7903 sel.cpMax = 999999;
\r
7904 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7910 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7914 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7918 case WM_MBUTTONDOWN:
\r
7919 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7920 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7922 case WM_RBUTTONUP:
\r
7923 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7924 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7925 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7929 hmenu = LoadMenu(hInst, "InputMenu");
\r
7930 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7931 if (sel.cpMin == sel.cpMax) {
\r
7932 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7933 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7935 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7936 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7938 pt.x = LOWORD(lParam);
\r
7939 pt.y = HIWORD(lParam);
\r
7940 MenuPopup(hwnd, pt, hmenu, -1);
\r
7944 switch (LOWORD(wParam)) {
\r
7946 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7948 case IDM_SelectAll:
\r
7950 sel.cpMax = -1; /*999999?*/
\r
7951 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7954 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7957 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7960 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7965 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7968 #define CO_MAX 100000
\r
7969 #define CO_TRIM 1000
\r
7972 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7974 static SnapData sd;
\r
7975 HWND hText, hInput;
\r
7977 static int sizeX, sizeY;
\r
7978 int newSizeX, newSizeY;
\r
7982 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7983 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7985 switch (message) {
\r
7987 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7989 ENLINK *pLink = (ENLINK*)lParam;
\r
7990 if (pLink->msg == WM_LBUTTONUP)
\r
7994 tr.chrg = pLink->chrg;
\r
7995 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7996 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7997 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7998 free(tr.lpstrText);
\r
8002 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8003 hwndConsole = hDlg;
\r
8005 consoleTextWindowProc = (WNDPROC)
\r
8006 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8007 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8008 consoleInputWindowProc = (WNDPROC)
\r
8009 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8010 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8011 Colorize(ColorNormal, TRUE);
\r
8012 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8013 ChangedConsoleFont();
\r
8014 GetClientRect(hDlg, &rect);
\r
8015 sizeX = rect.right;
\r
8016 sizeY = rect.bottom;
\r
8017 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8018 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8019 WINDOWPLACEMENT wp;
\r
8020 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8021 wp.length = sizeof(WINDOWPLACEMENT);
\r
8023 wp.showCmd = SW_SHOW;
\r
8024 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8025 wp.rcNormalPosition.left = wpConsole.x;
\r
8026 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8027 wp.rcNormalPosition.top = wpConsole.y;
\r
8028 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8029 SetWindowPlacement(hDlg, &wp);
\r
8032 // [HGM] Chessknight's change 2004-07-13
\r
8033 else { /* Determine Defaults */
\r
8034 WINDOWPLACEMENT wp;
\r
8035 wpConsole.x = winWidth + 1;
\r
8036 wpConsole.y = boardY;
\r
8037 wpConsole.width = screenWidth - winWidth;
\r
8038 wpConsole.height = winHeight;
\r
8039 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8040 wp.length = sizeof(WINDOWPLACEMENT);
\r
8042 wp.showCmd = SW_SHOW;
\r
8043 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8044 wp.rcNormalPosition.left = wpConsole.x;
\r
8045 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8046 wp.rcNormalPosition.top = wpConsole.y;
\r
8047 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8048 SetWindowPlacement(hDlg, &wp);
\r
8051 // Allow hText to highlight URLs and send notifications on them
\r
8052 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8053 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8054 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8055 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8069 if (IsIconic(hDlg)) break;
\r
8070 newSizeX = LOWORD(lParam);
\r
8071 newSizeY = HIWORD(lParam);
\r
8072 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8073 RECT rectText, rectInput;
\r
8075 int newTextHeight, newTextWidth;
\r
8076 GetWindowRect(hText, &rectText);
\r
8077 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8078 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8079 if (newTextHeight < 0) {
\r
8080 newSizeY += -newTextHeight;
\r
8081 newTextHeight = 0;
\r
8083 SetWindowPos(hText, NULL, 0, 0,
\r
8084 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8085 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8086 pt.x = rectInput.left;
\r
8087 pt.y = rectInput.top + newSizeY - sizeY;
\r
8088 ScreenToClient(hDlg, &pt);
\r
8089 SetWindowPos(hInput, NULL,
\r
8090 pt.x, pt.y, /* needs client coords */
\r
8091 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8092 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8098 case WM_GETMINMAXINFO:
\r
8099 /* Prevent resizing window too small */
\r
8100 mmi = (MINMAXINFO *) lParam;
\r
8101 mmi->ptMinTrackSize.x = 100;
\r
8102 mmi->ptMinTrackSize.y = 100;
\r
8105 /* [AS] Snapping */
\r
8106 case WM_ENTERSIZEMOVE:
\r
8107 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8110 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8113 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8115 case WM_EXITSIZEMOVE:
\r
8116 UpdateICSWidth(hText);
\r
8117 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8120 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8128 if (hwndConsole) return;
\r
8129 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8130 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8135 ConsoleOutput(char* data, int length, int forceVisible)
\r
8140 char buf[CO_MAX+1];
\r
8143 static int delayLF = 0;
\r
8144 CHARRANGE savesel, sel;
\r
8146 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8154 while (length--) {
\r
8162 } else if (*p == '\007') {
\r
8163 MyPlaySound(&sounds[(int)SoundBell]);
\r
8170 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8171 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8172 /* Save current selection */
\r
8173 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8174 exlen = GetWindowTextLength(hText);
\r
8175 /* Find out whether current end of text is visible */
\r
8176 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8177 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8178 /* Trim existing text if it's too long */
\r
8179 if (exlen + (q - buf) > CO_MAX) {
\r
8180 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8183 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8184 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8186 savesel.cpMin -= trim;
\r
8187 savesel.cpMax -= trim;
\r
8188 if (exlen < 0) exlen = 0;
\r
8189 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8190 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8192 /* Append the new text */
\r
8193 sel.cpMin = exlen;
\r
8194 sel.cpMax = exlen;
\r
8195 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8196 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8197 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8198 if (forceVisible || exlen == 0 ||
\r
8199 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8200 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8201 /* Scroll to make new end of text visible if old end of text
\r
8202 was visible or new text is an echo of user typein */
\r
8203 sel.cpMin = 9999999;
\r
8204 sel.cpMax = 9999999;
\r
8205 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8206 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8207 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8208 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8210 if (savesel.cpMax == exlen || forceVisible) {
\r
8211 /* Move insert point to new end of text if it was at the old
\r
8212 end of text or if the new text is an echo of user typein */
\r
8213 sel.cpMin = 9999999;
\r
8214 sel.cpMax = 9999999;
\r
8215 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8217 /* Restore previous selection */
\r
8218 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8220 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8227 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8231 COLORREF oldFg, oldBg;
\r
8235 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8237 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8238 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8239 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8242 rect.right = x + squareSize;
\r
8244 rect.bottom = y + squareSize;
\r
8247 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8248 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8249 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8250 &rect, str, strlen(str), NULL);
\r
8252 (void) SetTextColor(hdc, oldFg);
\r
8253 (void) SetBkColor(hdc, oldBg);
\r
8254 (void) SelectObject(hdc, oldFont);
\r
8258 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8259 RECT *rect, char *color, char *flagFell)
\r
8263 COLORREF oldFg, oldBg;
\r
8266 if (appData.clockMode) {
\r
8268 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8270 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8277 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8278 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8280 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8281 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8283 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8287 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8288 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8289 rect, str, strlen(str), NULL);
\r
8290 if(logoHeight > 0 && appData.clockMode) {
\r
8292 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8293 r.top = rect->top + logoHeight/2;
\r
8294 r.left = rect->left;
\r
8295 r.right = rect->right;
\r
8296 r.bottom = rect->bottom;
\r
8297 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8298 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8299 &r, str, strlen(str), NULL);
\r
8301 (void) SetTextColor(hdc, oldFg);
\r
8302 (void) SetBkColor(hdc, oldBg);
\r
8303 (void) SelectObject(hdc, oldFont);
\r
8308 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8314 if( count <= 0 ) {
\r
8315 if (appData.debugMode) {
\r
8316 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8319 return ERROR_INVALID_USER_BUFFER;
\r
8322 ResetEvent(ovl->hEvent);
\r
8323 ovl->Offset = ovl->OffsetHigh = 0;
\r
8324 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8328 err = GetLastError();
\r
8329 if (err == ERROR_IO_PENDING) {
\r
8330 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8334 err = GetLastError();
\r
8341 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8346 ResetEvent(ovl->hEvent);
\r
8347 ovl->Offset = ovl->OffsetHigh = 0;
\r
8348 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8352 err = GetLastError();
\r
8353 if (err == ERROR_IO_PENDING) {
\r
8354 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8358 err = GetLastError();
\r
8364 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8365 void CheckForInputBufferFull( InputSource * is )
\r
8367 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8368 /* Look for end of line */
\r
8369 char * p = is->buf;
\r
8371 while( p < is->next && *p != '\n' ) {
\r
8375 if( p >= is->next ) {
\r
8376 if (appData.debugMode) {
\r
8377 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8380 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8381 is->count = (DWORD) -1;
\r
8382 is->next = is->buf;
\r
8388 InputThread(LPVOID arg)
\r
8393 is = (InputSource *) arg;
\r
8394 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8395 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8396 while (is->hThread != NULL) {
\r
8397 is->error = DoReadFile(is->hFile, is->next,
\r
8398 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8399 &is->count, &ovl);
\r
8400 if (is->error == NO_ERROR) {
\r
8401 is->next += is->count;
\r
8403 if (is->error == ERROR_BROKEN_PIPE) {
\r
8404 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8407 is->count = (DWORD) -1;
\r
8408 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8413 CheckForInputBufferFull( is );
\r
8415 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8417 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8419 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8422 CloseHandle(ovl.hEvent);
\r
8423 CloseHandle(is->hFile);
\r
8425 if (appData.debugMode) {
\r
8426 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8433 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8435 NonOvlInputThread(LPVOID arg)
\r
8442 is = (InputSource *) arg;
\r
8443 while (is->hThread != NULL) {
\r
8444 is->error = ReadFile(is->hFile, is->next,
\r
8445 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8446 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8447 if (is->error == NO_ERROR) {
\r
8448 /* Change CRLF to LF */
\r
8449 if (is->next > is->buf) {
\r
8451 i = is->count + 1;
\r
8459 if (prev == '\r' && *p == '\n') {
\r
8471 if (is->error == ERROR_BROKEN_PIPE) {
\r
8472 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8475 is->count = (DWORD) -1;
\r
8479 CheckForInputBufferFull( is );
\r
8481 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8483 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8485 if (is->count < 0) break; /* Quit on error */
\r
8487 CloseHandle(is->hFile);
\r
8492 SocketInputThread(LPVOID arg)
\r
8496 is = (InputSource *) arg;
\r
8497 while (is->hThread != NULL) {
\r
8498 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8499 if ((int)is->count == SOCKET_ERROR) {
\r
8500 is->count = (DWORD) -1;
\r
8501 is->error = WSAGetLastError();
\r
8503 is->error = NO_ERROR;
\r
8504 is->next += is->count;
\r
8505 if (is->count == 0 && is->second == is) {
\r
8506 /* End of file on stderr; quit with no message */
\r
8510 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8512 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8514 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8520 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8524 is = (InputSource *) lParam;
\r
8525 if (is->lineByLine) {
\r
8526 /* Feed in lines one by one */
\r
8527 char *p = is->buf;
\r
8529 while (q < is->next) {
\r
8530 if (*q++ == '\n') {
\r
8531 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8536 /* Move any partial line to the start of the buffer */
\r
8538 while (p < is->next) {
\r
8543 if (is->error != NO_ERROR || is->count == 0) {
\r
8544 /* Notify backend of the error. Note: If there was a partial
\r
8545 line at the end, it is not flushed through. */
\r
8546 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8549 /* Feed in the whole chunk of input at once */
\r
8550 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8551 is->next = is->buf;
\r
8555 /*---------------------------------------------------------------------------*\
\r
8557 * Menu enables. Used when setting various modes.
\r
8559 \*---------------------------------------------------------------------------*/
\r
8567 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8569 while (enab->item > 0) {
\r
8570 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8575 Enables gnuEnables[] = {
\r
8576 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8580 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8581 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8590 Enables icsEnables[] = {
\r
8591 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8598 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8604 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8610 Enables zippyEnables[] = {
\r
8611 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8612 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8613 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8614 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8619 Enables ncpEnables[] = {
\r
8620 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8621 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8622 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8623 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8624 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8625 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8626 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8627 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8628 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8629 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8630 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8631 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8632 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8633 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8634 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8642 Enables trainingOnEnables[] = {
\r
8643 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8654 Enables trainingOffEnables[] = {
\r
8655 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8656 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8657 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8658 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8659 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8660 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8661 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8662 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8666 /* These modify either ncpEnables or gnuEnables */
\r
8667 Enables cmailEnables[] = {
\r
8668 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8671 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8672 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8674 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8678 Enables machineThinkingEnables[] = {
\r
8679 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8680 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8681 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8682 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8683 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8684 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8685 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8686 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8687 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8688 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8689 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8690 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8691 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8692 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8693 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8697 Enables userThinkingEnables[] = {
\r
8698 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8699 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8700 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8701 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8702 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8703 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8704 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8705 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8706 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8707 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8708 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8709 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8710 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8711 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8712 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8716 /*---------------------------------------------------------------------------*\
\r
8718 * Front-end interface functions exported by XBoard.
\r
8719 * Functions appear in same order as prototypes in frontend.h.
\r
8721 \*---------------------------------------------------------------------------*/
\r
8725 static UINT prevChecked = 0;
\r
8726 static int prevPausing = 0;
\r
8729 if (pausing != prevPausing) {
\r
8730 prevPausing = pausing;
\r
8731 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8732 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8733 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8736 switch (gameMode) {
\r
8737 case BeginningOfGame:
\r
8738 if (appData.icsActive)
\r
8739 nowChecked = IDM_IcsClient;
\r
8740 else if (appData.noChessProgram)
\r
8741 nowChecked = IDM_EditGame;
\r
8743 nowChecked = IDM_MachineBlack;
\r
8745 case MachinePlaysBlack:
\r
8746 nowChecked = IDM_MachineBlack;
\r
8748 case MachinePlaysWhite:
\r
8749 nowChecked = IDM_MachineWhite;
\r
8751 case TwoMachinesPlay:
\r
8752 nowChecked = IDM_TwoMachines;
\r
8755 nowChecked = IDM_AnalysisMode;
\r
8758 nowChecked = IDM_AnalyzeFile;
\r
8761 nowChecked = IDM_EditGame;
\r
8763 case PlayFromGameFile:
\r
8764 nowChecked = IDM_LoadGame;
\r
8766 case EditPosition:
\r
8767 nowChecked = IDM_EditPosition;
\r
8770 nowChecked = IDM_Training;
\r
8772 case IcsPlayingWhite:
\r
8773 case IcsPlayingBlack:
\r
8774 case IcsObserving:
\r
8776 nowChecked = IDM_IcsClient;
\r
8783 if (prevChecked != 0)
\r
8784 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8785 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8786 if (nowChecked != 0)
\r
8787 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8788 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8790 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8791 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8792 MF_BYCOMMAND|MF_ENABLED);
\r
8794 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8795 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8798 prevChecked = nowChecked;
\r
8800 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8801 if (appData.icsActive) {
\r
8802 if (appData.icsEngineAnalyze) {
\r
8803 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8804 MF_BYCOMMAND|MF_CHECKED);
\r
8806 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8807 MF_BYCOMMAND|MF_UNCHECKED);
\r
8815 HMENU hmenu = GetMenu(hwndMain);
\r
8816 SetMenuEnables(hmenu, icsEnables);
\r
8817 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8818 MF_BYPOSITION|MF_ENABLED);
\r
8820 if (appData.zippyPlay) {
\r
8821 SetMenuEnables(hmenu, zippyEnables);
\r
8822 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8823 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8824 MF_BYCOMMAND|MF_ENABLED);
\r
8832 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8838 HMENU hmenu = GetMenu(hwndMain);
\r
8839 SetMenuEnables(hmenu, ncpEnables);
\r
8840 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8841 MF_BYPOSITION|MF_GRAYED);
\r
8842 DrawMenuBar(hwndMain);
\r
8848 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8852 SetTrainingModeOn()
\r
8855 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8856 for (i = 0; i < N_BUTTONS; i++) {
\r
8857 if (buttonDesc[i].hwnd != NULL)
\r
8858 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8863 VOID SetTrainingModeOff()
\r
8866 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8867 for (i = 0; i < N_BUTTONS; i++) {
\r
8868 if (buttonDesc[i].hwnd != NULL)
\r
8869 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8875 SetUserThinkingEnables()
\r
8877 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8881 SetMachineThinkingEnables()
\r
8883 HMENU hMenu = GetMenu(hwndMain);
\r
8884 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8886 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8888 if (gameMode == MachinePlaysBlack) {
\r
8889 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8890 } else if (gameMode == MachinePlaysWhite) {
\r
8891 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8892 } else if (gameMode == TwoMachinesPlay) {
\r
8893 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8899 DisplayTitle(char *str)
\r
8901 char title[MSG_SIZ], *host;
\r
8902 if (str[0] != NULLCHAR) {
\r
8903 strcpy(title, str);
\r
8904 } else if (appData.icsActive) {
\r
8905 if (appData.icsCommPort[0] != NULLCHAR)
\r
8908 host = appData.icsHost;
\r
8909 sprintf(title, "%s: %s", szTitle, host);
\r
8910 } else if (appData.noChessProgram) {
\r
8911 strcpy(title, szTitle);
\r
8913 strcpy(title, szTitle);
\r
8914 strcat(title, ": ");
\r
8915 strcat(title, first.tidy);
\r
8917 SetWindowText(hwndMain, title);
\r
8922 DisplayMessage(char *str1, char *str2)
\r
8926 int remain = MESSAGE_TEXT_MAX - 1;
\r
8929 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8930 messageText[0] = NULLCHAR;
\r
8932 len = strlen(str1);
\r
8933 if (len > remain) len = remain;
\r
8934 strncpy(messageText, str1, len);
\r
8935 messageText[len] = NULLCHAR;
\r
8938 if (*str2 && remain >= 2) {
\r
8940 strcat(messageText, " ");
\r
8943 len = strlen(str2);
\r
8944 if (len > remain) len = remain;
\r
8945 strncat(messageText, str2, len);
\r
8947 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8949 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8953 hdc = GetDC(hwndMain);
\r
8954 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8955 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8956 &messageRect, messageText, strlen(messageText), NULL);
\r
8957 (void) SelectObject(hdc, oldFont);
\r
8958 (void) ReleaseDC(hwndMain, hdc);
\r
8962 DisplayError(char *str, int error)
\r
8964 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8970 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8971 NULL, error, LANG_NEUTRAL,
\r
8972 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8974 sprintf(buf, "%s:\n%s", str, buf2);
\r
8976 ErrorMap *em = errmap;
\r
8977 while (em->err != 0 && em->err != error) em++;
\r
8978 if (em->err != 0) {
\r
8979 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8981 sprintf(buf, "%s:\nError code %d", str, error);
\r
8986 ErrorPopUp("Error", buf);
\r
8991 DisplayMoveError(char *str)
\r
8993 fromX = fromY = -1;
\r
8994 ClearHighlights();
\r
8995 DrawPosition(FALSE, NULL);
\r
8996 if (appData.popupMoveErrors) {
\r
8997 ErrorPopUp("Error", str);
\r
8999 DisplayMessage(str, "");
\r
9000 moveErrorMessageUp = TRUE;
\r
9005 DisplayFatalError(char *str, int error, int exitStatus)
\r
9007 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9009 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9012 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9013 NULL, error, LANG_NEUTRAL,
\r
9014 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9016 sprintf(buf, "%s:\n%s", str, buf2);
\r
9018 ErrorMap *em = errmap;
\r
9019 while (em->err != 0 && em->err != error) em++;
\r
9020 if (em->err != 0) {
\r
9021 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9023 sprintf(buf, "%s:\nError code %d", str, error);
\r
9028 if (appData.debugMode) {
\r
9029 fprintf(debugFP, "%s: %s\n", label, str);
\r
9031 if (appData.popupExitMessage) {
\r
9032 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9033 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9035 ExitEvent(exitStatus);
\r
9040 DisplayInformation(char *str)
\r
9042 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9047 DisplayNote(char *str)
\r
9049 ErrorPopUp("Note", str);
\r
9054 char *title, *question, *replyPrefix;
\r
9059 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9061 static QuestionParams *qp;
\r
9062 char reply[MSG_SIZ];
\r
9065 switch (message) {
\r
9066 case WM_INITDIALOG:
\r
9067 qp = (QuestionParams *) lParam;
\r
9068 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9069 SetWindowText(hDlg, qp->title);
\r
9070 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9071 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9075 switch (LOWORD(wParam)) {
\r
9077 strcpy(reply, qp->replyPrefix);
\r
9078 if (*reply) strcat(reply, " ");
\r
9079 len = strlen(reply);
\r
9080 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9081 strcat(reply, "\n");
\r
9082 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9083 EndDialog(hDlg, TRUE);
\r
9084 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9087 EndDialog(hDlg, FALSE);
\r
9098 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9100 QuestionParams qp;
\r
9104 qp.question = question;
\r
9105 qp.replyPrefix = replyPrefix;
\r
9107 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9108 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9109 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9110 FreeProcInstance(lpProc);
\r
9113 /* [AS] Pick FRC position */
\r
9114 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9116 static int * lpIndexFRC;
\r
9122 case WM_INITDIALOG:
\r
9123 lpIndexFRC = (int *) lParam;
\r
9125 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9127 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9128 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9129 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9130 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9135 switch( LOWORD(wParam) ) {
\r
9137 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9138 EndDialog( hDlg, 0 );
\r
9139 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9142 EndDialog( hDlg, 1 );
\r
9144 case IDC_NFG_Edit:
\r
9145 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9146 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9148 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9151 case IDC_NFG_Random:
\r
9152 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9153 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9166 int index = appData.defaultFrcPosition;
\r
9167 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9169 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9171 if( result == 0 ) {
\r
9172 appData.defaultFrcPosition = index;
\r
9178 /* [AS] Game list options */
\r
9184 static GLT_Item GLT_ItemInfo[] = {
\r
9185 { GLT_EVENT, "Event" },
\r
9186 { GLT_SITE, "Site" },
\r
9187 { GLT_DATE, "Date" },
\r
9188 { GLT_ROUND, "Round" },
\r
9189 { GLT_PLAYERS, "Players" },
\r
9190 { GLT_RESULT, "Result" },
\r
9191 { GLT_WHITE_ELO, "White Rating" },
\r
9192 { GLT_BLACK_ELO, "Black Rating" },
\r
9193 { GLT_TIME_CONTROL,"Time Control" },
\r
9194 { GLT_VARIANT, "Variant" },
\r
9195 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9196 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9200 const char * GLT_FindItem( char id )
\r
9202 const char * result = 0;
\r
9204 GLT_Item * list = GLT_ItemInfo;
\r
9206 while( list->id != 0 ) {
\r
9207 if( list->id == id ) {
\r
9208 result = list->name;
\r
9218 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9220 const char * name = GLT_FindItem( id );
\r
9223 if( index >= 0 ) {
\r
9224 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9227 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9232 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9236 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9239 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9243 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9245 pc = GLT_ALL_TAGS;
\r
9248 if( strchr( tags, *pc ) == 0 ) {
\r
9249 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9254 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9257 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9259 char result = '\0';
\r
9262 GLT_Item * list = GLT_ItemInfo;
\r
9264 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9265 while( list->id != 0 ) {
\r
9266 if( strcmp( list->name, name ) == 0 ) {
\r
9267 result = list->id;
\r
9278 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9280 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9281 int idx2 = idx1 + delta;
\r
9282 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9284 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9287 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9288 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9289 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9290 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9294 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9296 static char glt[64];
\r
9297 static char * lpUserGLT;
\r
9301 case WM_INITDIALOG:
\r
9302 lpUserGLT = (char *) lParam;
\r
9304 strcpy( glt, lpUserGLT );
\r
9306 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9308 /* Initialize list */
\r
9309 GLT_TagsToList( hDlg, glt );
\r
9311 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9316 switch( LOWORD(wParam) ) {
\r
9319 char * pc = lpUserGLT;
\r
9321 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9325 id = GLT_ListItemToTag( hDlg, idx );
\r
9329 } while( id != '\0' );
\r
9331 EndDialog( hDlg, 0 );
\r
9334 EndDialog( hDlg, 1 );
\r
9337 case IDC_GLT_Default:
\r
9338 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9339 GLT_TagsToList( hDlg, glt );
\r
9342 case IDC_GLT_Restore:
\r
9343 strcpy( glt, lpUserGLT );
\r
9344 GLT_TagsToList( hDlg, glt );
\r
9348 GLT_MoveSelection( hDlg, -1 );
\r
9351 case IDC_GLT_Down:
\r
9352 GLT_MoveSelection( hDlg, +1 );
\r
9362 int GameListOptions()
\r
9366 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9368 strcpy( glt, appData.gameListTags );
\r
9370 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9372 if( result == 0 ) {
\r
9373 /* [AS] Memory leak here! */
\r
9374 appData.gameListTags = strdup( glt );
\r
9382 DisplayIcsInteractionTitle(char *str)
\r
9384 char consoleTitle[MSG_SIZ];
\r
9386 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9387 SetWindowText(hwndConsole, consoleTitle);
\r
9391 DrawPosition(int fullRedraw, Board board)
\r
9393 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9396 void NotifyFrontendLogin()
\r
9399 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9405 fromX = fromY = -1;
\r
9406 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9407 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9408 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9409 dragInfo.lastpos = dragInfo.pos;
\r
9410 dragInfo.start.x = dragInfo.start.y = -1;
\r
9411 dragInfo.from = dragInfo.start;
\r
9413 DrawPosition(TRUE, NULL);
\r
9419 CommentPopUp(char *title, char *str)
\r
9421 HWND hwnd = GetActiveWindow();
\r
9422 EitherCommentPopUp(0, title, str, FALSE);
\r
9424 SetActiveWindow(hwnd);
\r
9428 CommentPopDown(void)
\r
9430 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9431 if (commentDialog) {
\r
9432 ShowWindow(commentDialog, SW_HIDE);
\r
9434 commentUp = FALSE;
\r
9438 EditCommentPopUp(int index, char *title, char *str)
\r
9440 EitherCommentPopUp(index, title, str, TRUE);
\r
9447 MyPlaySound(&sounds[(int)SoundMove]);
\r
9450 VOID PlayIcsWinSound()
\r
9452 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9455 VOID PlayIcsLossSound()
\r
9457 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9460 VOID PlayIcsDrawSound()
\r
9462 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9465 VOID PlayIcsUnfinishedSound()
\r
9467 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9473 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9481 consoleEcho = TRUE;
\r
9482 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9483 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9484 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9493 consoleEcho = FALSE;
\r
9494 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9495 /* This works OK: set text and background both to the same color */
\r
9497 cf.crTextColor = COLOR_ECHOOFF;
\r
9498 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9499 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9502 /* No Raw()...? */
\r
9504 void Colorize(ColorClass cc, int continuation)
\r
9506 currentColorClass = cc;
\r
9507 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9508 consoleCF.crTextColor = textAttribs[cc].color;
\r
9509 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9510 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9516 static char buf[MSG_SIZ];
\r
9517 DWORD bufsiz = MSG_SIZ;
\r
9519 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9520 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9522 if (!GetUserName(buf, &bufsiz)) {
\r
9523 /*DisplayError("Error getting user name", GetLastError());*/
\r
9524 strcpy(buf, "User");
\r
9532 static char buf[MSG_SIZ];
\r
9533 DWORD bufsiz = MSG_SIZ;
\r
9535 if (!GetComputerName(buf, &bufsiz)) {
\r
9536 /*DisplayError("Error getting host name", GetLastError());*/
\r
9537 strcpy(buf, "Unknown");
\r
9544 ClockTimerRunning()
\r
9546 return clockTimerEvent != 0;
\r
9552 if (clockTimerEvent == 0) return FALSE;
\r
9553 KillTimer(hwndMain, clockTimerEvent);
\r
9554 clockTimerEvent = 0;
\r
9559 StartClockTimer(long millisec)
\r
9561 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9562 (UINT) millisec, NULL);
\r
9566 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9569 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9571 if(appData.noGUI) return;
\r
9572 hdc = GetDC(hwndMain);
\r
9573 if (!IsIconic(hwndMain)) {
\r
9574 DisplayAClock(hdc, timeRemaining, highlight,
\r
9575 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9577 if (highlight && iconCurrent == iconBlack) {
\r
9578 iconCurrent = iconWhite;
\r
9579 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9580 if (IsIconic(hwndMain)) {
\r
9581 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9584 (void) ReleaseDC(hwndMain, hdc);
\r
9586 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9590 DisplayBlackClock(long timeRemaining, int highlight)
\r
9593 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9595 if(appData.noGUI) return;
\r
9596 hdc = GetDC(hwndMain);
\r
9597 if (!IsIconic(hwndMain)) {
\r
9598 DisplayAClock(hdc, timeRemaining, highlight,
\r
9599 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9601 if (highlight && iconCurrent == iconWhite) {
\r
9602 iconCurrent = iconBlack;
\r
9603 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9604 if (IsIconic(hwndMain)) {
\r
9605 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9608 (void) ReleaseDC(hwndMain, hdc);
\r
9610 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9615 LoadGameTimerRunning()
\r
9617 return loadGameTimerEvent != 0;
\r
9621 StopLoadGameTimer()
\r
9623 if (loadGameTimerEvent == 0) return FALSE;
\r
9624 KillTimer(hwndMain, loadGameTimerEvent);
\r
9625 loadGameTimerEvent = 0;
\r
9630 StartLoadGameTimer(long millisec)
\r
9632 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9633 (UINT) millisec, NULL);
\r
9641 char fileTitle[MSG_SIZ];
\r
9643 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9644 f = OpenFileDialog(hwndMain, "a", defName,
\r
9645 appData.oldSaveStyle ? "gam" : "pgn",
\r
9647 "Save Game to File", NULL, fileTitle, NULL);
\r
9649 SaveGame(f, 0, "");
\r
9656 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9658 if (delayedTimerEvent != 0) {
\r
9659 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9660 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9662 KillTimer(hwndMain, delayedTimerEvent);
\r
9663 delayedTimerEvent = 0;
\r
9664 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9665 delayedTimerCallback();
\r
9667 delayedTimerCallback = cb;
\r
9668 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9669 (UINT) millisec, NULL);
\r
9672 DelayedEventCallback
\r
9675 if (delayedTimerEvent) {
\r
9676 return delayedTimerCallback;
\r
9683 CancelDelayedEvent()
\r
9685 if (delayedTimerEvent) {
\r
9686 KillTimer(hwndMain, delayedTimerEvent);
\r
9687 delayedTimerEvent = 0;
\r
9691 DWORD GetWin32Priority(int nice)
\r
9692 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9694 REALTIME_PRIORITY_CLASS 0x00000100
\r
9695 HIGH_PRIORITY_CLASS 0x00000080
\r
9696 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9697 NORMAL_PRIORITY_CLASS 0x00000020
\r
9698 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9699 IDLE_PRIORITY_CLASS 0x00000040
\r
9701 if (nice < -15) return 0x00000080;
\r
9702 if (nice < 0) return 0x00008000;
\r
9703 if (nice == 0) return 0x00000020;
\r
9704 if (nice < 15) return 0x00004000;
\r
9705 return 0x00000040;
\r
9708 /* Start a child process running the given program.
\r
9709 The process's standard output can be read from "from", and its
\r
9710 standard input can be written to "to".
\r
9711 Exit with fatal error if anything goes wrong.
\r
9712 Returns an opaque pointer that can be used to destroy the process
\r
9716 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9718 #define BUFSIZE 4096
\r
9720 HANDLE hChildStdinRd, hChildStdinWr,
\r
9721 hChildStdoutRd, hChildStdoutWr;
\r
9722 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9723 SECURITY_ATTRIBUTES saAttr;
\r
9725 PROCESS_INFORMATION piProcInfo;
\r
9726 STARTUPINFO siStartInfo;
\r
9728 char buf[MSG_SIZ];
\r
9731 if (appData.debugMode) {
\r
9732 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9737 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9738 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9739 saAttr.bInheritHandle = TRUE;
\r
9740 saAttr.lpSecurityDescriptor = NULL;
\r
9743 * The steps for redirecting child's STDOUT:
\r
9744 * 1. Create anonymous pipe to be STDOUT for child.
\r
9745 * 2. Create a noninheritable duplicate of read handle,
\r
9746 * and close the inheritable read handle.
\r
9749 /* Create a pipe for the child's STDOUT. */
\r
9750 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9751 return GetLastError();
\r
9754 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9755 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9756 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9757 FALSE, /* not inherited */
\r
9758 DUPLICATE_SAME_ACCESS);
\r
9760 return GetLastError();
\r
9762 CloseHandle(hChildStdoutRd);
\r
9765 * The steps for redirecting child's STDIN:
\r
9766 * 1. Create anonymous pipe to be STDIN for child.
\r
9767 * 2. Create a noninheritable duplicate of write handle,
\r
9768 * and close the inheritable write handle.
\r
9771 /* Create a pipe for the child's STDIN. */
\r
9772 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9773 return GetLastError();
\r
9776 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9777 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9778 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9779 FALSE, /* not inherited */
\r
9780 DUPLICATE_SAME_ACCESS);
\r
9782 return GetLastError();
\r
9784 CloseHandle(hChildStdinWr);
\r
9786 /* Arrange to (1) look in dir for the child .exe file, and
\r
9787 * (2) have dir be the child's working directory. Interpret
\r
9788 * dir relative to the directory WinBoard loaded from. */
\r
9789 GetCurrentDirectory(MSG_SIZ, buf);
\r
9790 SetCurrentDirectory(installDir);
\r
9791 SetCurrentDirectory(dir);
\r
9793 /* Now create the child process. */
\r
9795 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9796 siStartInfo.lpReserved = NULL;
\r
9797 siStartInfo.lpDesktop = NULL;
\r
9798 siStartInfo.lpTitle = NULL;
\r
9799 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9800 siStartInfo.cbReserved2 = 0;
\r
9801 siStartInfo.lpReserved2 = NULL;
\r
9802 siStartInfo.hStdInput = hChildStdinRd;
\r
9803 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9804 siStartInfo.hStdError = hChildStdoutWr;
\r
9806 fSuccess = CreateProcess(NULL,
\r
9807 cmdLine, /* command line */
\r
9808 NULL, /* process security attributes */
\r
9809 NULL, /* primary thread security attrs */
\r
9810 TRUE, /* handles are inherited */
\r
9811 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9812 NULL, /* use parent's environment */
\r
9814 &siStartInfo, /* STARTUPINFO pointer */
\r
9815 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9817 err = GetLastError();
\r
9818 SetCurrentDirectory(buf); /* return to prev directory */
\r
9823 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9824 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9825 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9828 /* Close the handles we don't need in the parent */
\r
9829 CloseHandle(piProcInfo.hThread);
\r
9830 CloseHandle(hChildStdinRd);
\r
9831 CloseHandle(hChildStdoutWr);
\r
9833 /* Prepare return value */
\r
9834 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9835 cp->kind = CPReal;
\r
9836 cp->hProcess = piProcInfo.hProcess;
\r
9837 cp->pid = piProcInfo.dwProcessId;
\r
9838 cp->hFrom = hChildStdoutRdDup;
\r
9839 cp->hTo = hChildStdinWrDup;
\r
9841 *pr = (void *) cp;
\r
9843 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9844 2000 where engines sometimes don't see the initial command(s)
\r
9845 from WinBoard and hang. I don't understand how that can happen,
\r
9846 but the Sleep is harmless, so I've put it in. Others have also
\r
9847 reported what may be the same problem, so hopefully this will fix
\r
9848 it for them too. */
\r
9856 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9858 ChildProc *cp; int result;
\r
9860 cp = (ChildProc *) pr;
\r
9861 if (cp == NULL) return;
\r
9863 switch (cp->kind) {
\r
9865 /* TerminateProcess is considered harmful, so... */
\r
9866 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9867 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9868 /* The following doesn't work because the chess program
\r
9869 doesn't "have the same console" as WinBoard. Maybe
\r
9870 we could arrange for this even though neither WinBoard
\r
9871 nor the chess program uses a console for stdio? */
\r
9872 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9874 /* [AS] Special termination modes for misbehaving programs... */
\r
9875 if( signal == 9 ) {
\r
9876 result = TerminateProcess( cp->hProcess, 0 );
\r
9878 if ( appData.debugMode) {
\r
9879 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9882 else if( signal == 10 ) {
\r
9883 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9885 if( dw != WAIT_OBJECT_0 ) {
\r
9886 result = TerminateProcess( cp->hProcess, 0 );
\r
9888 if ( appData.debugMode) {
\r
9889 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9895 CloseHandle(cp->hProcess);
\r
9899 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9903 closesocket(cp->sock);
\r
9908 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9909 closesocket(cp->sock);
\r
9910 closesocket(cp->sock2);
\r
9918 InterruptChildProcess(ProcRef pr)
\r
9922 cp = (ChildProc *) pr;
\r
9923 if (cp == NULL) return;
\r
9924 switch (cp->kind) {
\r
9926 /* The following doesn't work because the chess program
\r
9927 doesn't "have the same console" as WinBoard. Maybe
\r
9928 we could arrange for this even though neither WinBoard
\r
9929 nor the chess program uses a console for stdio */
\r
9930 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9935 /* Can't interrupt */
\r
9939 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9946 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9948 char cmdLine[MSG_SIZ];
\r
9950 if (port[0] == NULLCHAR) {
\r
9951 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9953 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9955 return StartChildProcess(cmdLine, "", pr);
\r
9959 /* Code to open TCP sockets */
\r
9962 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9967 struct sockaddr_in sa, mysa;
\r
9968 struct hostent FAR *hp;
\r
9969 unsigned short uport;
\r
9970 WORD wVersionRequested;
\r
9973 /* Initialize socket DLL */
\r
9974 wVersionRequested = MAKEWORD(1, 1);
\r
9975 err = WSAStartup(wVersionRequested, &wsaData);
\r
9976 if (err != 0) return err;
\r
9979 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9980 err = WSAGetLastError();
\r
9985 /* Bind local address using (mostly) don't-care values.
\r
9987 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9988 mysa.sin_family = AF_INET;
\r
9989 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9990 uport = (unsigned short) 0;
\r
9991 mysa.sin_port = htons(uport);
\r
9992 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9993 == SOCKET_ERROR) {
\r
9994 err = WSAGetLastError();
\r
9999 /* Resolve remote host name */
\r
10000 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10001 if (!(hp = gethostbyname(host))) {
\r
10002 unsigned int b0, b1, b2, b3;
\r
10004 err = WSAGetLastError();
\r
10006 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10007 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10008 hp->h_addrtype = AF_INET;
\r
10009 hp->h_length = 4;
\r
10010 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10011 hp->h_addr_list[0] = (char *) malloc(4);
\r
10012 hp->h_addr_list[0][0] = (char) b0;
\r
10013 hp->h_addr_list[0][1] = (char) b1;
\r
10014 hp->h_addr_list[0][2] = (char) b2;
\r
10015 hp->h_addr_list[0][3] = (char) b3;
\r
10021 sa.sin_family = hp->h_addrtype;
\r
10022 uport = (unsigned short) atoi(port);
\r
10023 sa.sin_port = htons(uport);
\r
10024 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10026 /* Make connection */
\r
10027 if (connect(s, (struct sockaddr *) &sa,
\r
10028 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10029 err = WSAGetLastError();
\r
10034 /* Prepare return value */
\r
10035 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10036 cp->kind = CPSock;
\r
10038 *pr = (ProcRef *) cp;
\r
10044 OpenCommPort(char *name, ProcRef *pr)
\r
10049 char fullname[MSG_SIZ];
\r
10051 if (*name != '\\')
\r
10052 sprintf(fullname, "\\\\.\\%s", name);
\r
10054 strcpy(fullname, name);
\r
10056 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10057 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10058 if (h == (HANDLE) -1) {
\r
10059 return GetLastError();
\r
10063 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10065 /* Accumulate characters until a 100ms pause, then parse */
\r
10066 ct.ReadIntervalTimeout = 100;
\r
10067 ct.ReadTotalTimeoutMultiplier = 0;
\r
10068 ct.ReadTotalTimeoutConstant = 0;
\r
10069 ct.WriteTotalTimeoutMultiplier = 0;
\r
10070 ct.WriteTotalTimeoutConstant = 0;
\r
10071 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10073 /* Prepare return value */
\r
10074 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10075 cp->kind = CPComm;
\r
10078 *pr = (ProcRef *) cp;
\r
10084 OpenLoopback(ProcRef *pr)
\r
10086 DisplayFatalError("Not implemented", 0, 1);
\r
10092 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10096 SOCKET s, s2, s3;
\r
10097 struct sockaddr_in sa, mysa;
\r
10098 struct hostent FAR *hp;
\r
10099 unsigned short uport;
\r
10100 WORD wVersionRequested;
\r
10103 char stderrPortStr[MSG_SIZ];
\r
10105 /* Initialize socket DLL */
\r
10106 wVersionRequested = MAKEWORD(1, 1);
\r
10107 err = WSAStartup(wVersionRequested, &wsaData);
\r
10108 if (err != 0) return err;
\r
10110 /* Resolve remote host name */
\r
10111 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10112 if (!(hp = gethostbyname(host))) {
\r
10113 unsigned int b0, b1, b2, b3;
\r
10115 err = WSAGetLastError();
\r
10117 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10118 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10119 hp->h_addrtype = AF_INET;
\r
10120 hp->h_length = 4;
\r
10121 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10122 hp->h_addr_list[0] = (char *) malloc(4);
\r
10123 hp->h_addr_list[0][0] = (char) b0;
\r
10124 hp->h_addr_list[0][1] = (char) b1;
\r
10125 hp->h_addr_list[0][2] = (char) b2;
\r
10126 hp->h_addr_list[0][3] = (char) b3;
\r
10132 sa.sin_family = hp->h_addrtype;
\r
10133 uport = (unsigned short) 514;
\r
10134 sa.sin_port = htons(uport);
\r
10135 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10137 /* Bind local socket to unused "privileged" port address
\r
10139 s = INVALID_SOCKET;
\r
10140 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10141 mysa.sin_family = AF_INET;
\r
10142 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10143 for (fromPort = 1023;; fromPort--) {
\r
10144 if (fromPort < 0) {
\r
10146 return WSAEADDRINUSE;
\r
10148 if (s == INVALID_SOCKET) {
\r
10149 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10150 err = WSAGetLastError();
\r
10155 uport = (unsigned short) fromPort;
\r
10156 mysa.sin_port = htons(uport);
\r
10157 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10158 == SOCKET_ERROR) {
\r
10159 err = WSAGetLastError();
\r
10160 if (err == WSAEADDRINUSE) continue;
\r
10164 if (connect(s, (struct sockaddr *) &sa,
\r
10165 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10166 err = WSAGetLastError();
\r
10167 if (err == WSAEADDRINUSE) {
\r
10178 /* Bind stderr local socket to unused "privileged" port address
\r
10180 s2 = INVALID_SOCKET;
\r
10181 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10182 mysa.sin_family = AF_INET;
\r
10183 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10184 for (fromPort = 1023;; fromPort--) {
\r
10185 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10186 if (fromPort < 0) {
\r
10187 (void) closesocket(s);
\r
10189 return WSAEADDRINUSE;
\r
10191 if (s2 == INVALID_SOCKET) {
\r
10192 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10193 err = WSAGetLastError();
\r
10199 uport = (unsigned short) fromPort;
\r
10200 mysa.sin_port = htons(uport);
\r
10201 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10202 == SOCKET_ERROR) {
\r
10203 err = WSAGetLastError();
\r
10204 if (err == WSAEADDRINUSE) continue;
\r
10205 (void) closesocket(s);
\r
10209 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10210 err = WSAGetLastError();
\r
10211 if (err == WSAEADDRINUSE) {
\r
10213 s2 = INVALID_SOCKET;
\r
10216 (void) closesocket(s);
\r
10217 (void) closesocket(s2);
\r
10223 prevStderrPort = fromPort; // remember port used
\r
10224 sprintf(stderrPortStr, "%d", fromPort);
\r
10226 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10227 err = WSAGetLastError();
\r
10228 (void) closesocket(s);
\r
10229 (void) closesocket(s2);
\r
10234 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10235 err = WSAGetLastError();
\r
10236 (void) closesocket(s);
\r
10237 (void) closesocket(s2);
\r
10241 if (*user == NULLCHAR) user = UserName();
\r
10242 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10243 err = WSAGetLastError();
\r
10244 (void) closesocket(s);
\r
10245 (void) closesocket(s2);
\r
10249 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10250 err = WSAGetLastError();
\r
10251 (void) closesocket(s);
\r
10252 (void) closesocket(s2);
\r
10257 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10258 err = WSAGetLastError();
\r
10259 (void) closesocket(s);
\r
10260 (void) closesocket(s2);
\r
10264 (void) closesocket(s2); /* Stop listening */
\r
10266 /* Prepare return value */
\r
10267 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10268 cp->kind = CPRcmd;
\r
10271 *pr = (ProcRef *) cp;
\r
10278 AddInputSource(ProcRef pr, int lineByLine,
\r
10279 InputCallback func, VOIDSTAR closure)
\r
10281 InputSource *is, *is2 = NULL;
\r
10282 ChildProc *cp = (ChildProc *) pr;
\r
10284 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10285 is->lineByLine = lineByLine;
\r
10287 is->closure = closure;
\r
10288 is->second = NULL;
\r
10289 is->next = is->buf;
\r
10290 if (pr == NoProc) {
\r
10291 is->kind = CPReal;
\r
10292 consoleInputSource = is;
\r
10294 is->kind = cp->kind;
\r
10296 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10297 we create all threads suspended so that the is->hThread variable can be
\r
10298 safely assigned, then let the threads start with ResumeThread.
\r
10300 switch (cp->kind) {
\r
10302 is->hFile = cp->hFrom;
\r
10303 cp->hFrom = NULL; /* now owned by InputThread */
\r
10305 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10306 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10310 is->hFile = cp->hFrom;
\r
10311 cp->hFrom = NULL; /* now owned by InputThread */
\r
10313 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10314 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10318 is->sock = cp->sock;
\r
10320 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10321 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10325 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10327 is->sock = cp->sock;
\r
10328 is->second = is2;
\r
10329 is2->sock = cp->sock2;
\r
10330 is2->second = is2;
\r
10332 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10333 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10335 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10336 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10340 if( is->hThread != NULL ) {
\r
10341 ResumeThread( is->hThread );
\r
10344 if( is2 != NULL && is2->hThread != NULL ) {
\r
10345 ResumeThread( is2->hThread );
\r
10349 return (InputSourceRef) is;
\r
10353 RemoveInputSource(InputSourceRef isr)
\r
10357 is = (InputSource *) isr;
\r
10358 is->hThread = NULL; /* tell thread to stop */
\r
10359 CloseHandle(is->hThread);
\r
10360 if (is->second != NULL) {
\r
10361 is->second->hThread = NULL;
\r
10362 CloseHandle(is->second->hThread);
\r
10366 int no_wrap(char *message, int count)
\r
10368 ConsoleOutput(message, count, FALSE);
\r
10373 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10376 int outCount = SOCKET_ERROR;
\r
10377 ChildProc *cp = (ChildProc *) pr;
\r
10378 static OVERLAPPED ovl;
\r
10379 static int line = 0;
\r
10381 if (pr == NoProc)
\r
10383 if (appData.noJoin || !appData.useInternalWrap)
\r
10384 return no_wrap(message, count);
\r
10387 int width = get_term_width();
\r
10388 int len = wrap(NULL, message, count, width, &line);
\r
10389 char *msg = malloc(len);
\r
10393 return no_wrap(message, count);
\r
10396 dbgchk = wrap(msg, message, count, width, &line);
\r
10397 if (dbgchk != len && appData.debugMode)
\r
10398 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10399 ConsoleOutput(msg, len, FALSE);
\r
10406 if (ovl.hEvent == NULL) {
\r
10407 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10409 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10411 switch (cp->kind) {
\r
10414 outCount = send(cp->sock, message, count, 0);
\r
10415 if (outCount == SOCKET_ERROR) {
\r
10416 *outError = WSAGetLastError();
\r
10418 *outError = NO_ERROR;
\r
10423 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10424 &dOutCount, NULL)) {
\r
10425 *outError = NO_ERROR;
\r
10426 outCount = (int) dOutCount;
\r
10428 *outError = GetLastError();
\r
10433 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10434 &dOutCount, &ovl);
\r
10435 if (*outError == NO_ERROR) {
\r
10436 outCount = (int) dOutCount;
\r
10444 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10447 /* Ignore delay, not implemented for WinBoard */
\r
10448 return OutputToProcess(pr, message, count, outError);
\r
10453 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10454 char *buf, int count, int error)
\r
10456 DisplayFatalError("Not implemented", 0, 1);
\r
10459 /* see wgamelist.c for Game List functions */
\r
10460 /* see wedittags.c for Edit Tags functions */
\r
10467 char buf[MSG_SIZ];
\r
10470 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10471 f = fopen(buf, "r");
\r
10473 ProcessICSInitScript(f);
\r
10481 StartAnalysisClock()
\r
10483 if (analysisTimerEvent) return;
\r
10484 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10485 (UINT) 2000, NULL);
\r
10489 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10491 static HANDLE hwndText;
\r
10493 static int sizeX, sizeY;
\r
10494 int newSizeX, newSizeY, flags;
\r
10497 switch (message) {
\r
10498 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10499 /* Initialize the dialog items */
\r
10500 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10501 SetWindowText(hDlg, analysisTitle);
\r
10502 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10503 /* Size and position the dialog */
\r
10504 if (!analysisDialog) {
\r
10505 analysisDialog = hDlg;
\r
10506 flags = SWP_NOZORDER;
\r
10507 GetClientRect(hDlg, &rect);
\r
10508 sizeX = rect.right;
\r
10509 sizeY = rect.bottom;
\r
10510 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10511 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10512 WINDOWPLACEMENT wp;
\r
10513 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10514 wp.length = sizeof(WINDOWPLACEMENT);
\r
10516 wp.showCmd = SW_SHOW;
\r
10517 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10518 wp.rcNormalPosition.left = analysisX;
\r
10519 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10520 wp.rcNormalPosition.top = analysisY;
\r
10521 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10522 SetWindowPlacement(hDlg, &wp);
\r
10524 GetClientRect(hDlg, &rect);
\r
10525 newSizeX = rect.right;
\r
10526 newSizeY = rect.bottom;
\r
10527 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10528 newSizeX, newSizeY);
\r
10529 sizeX = newSizeX;
\r
10530 sizeY = newSizeY;
\r
10535 case WM_COMMAND: /* message: received a command */
\r
10536 switch (LOWORD(wParam)) {
\r
10538 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10539 ExitAnalyzeMode();
\r
10551 newSizeX = LOWORD(lParam);
\r
10552 newSizeY = HIWORD(lParam);
\r
10553 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10554 sizeX = newSizeX;
\r
10555 sizeY = newSizeY;
\r
10558 case WM_GETMINMAXINFO:
\r
10559 /* Prevent resizing window too small */
\r
10560 mmi = (MINMAXINFO *) lParam;
\r
10561 mmi->ptMinTrackSize.x = 100;
\r
10562 mmi->ptMinTrackSize.y = 100;
\r
10569 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10571 highlightInfo.sq[0].x = fromX;
\r
10572 highlightInfo.sq[0].y = fromY;
\r
10573 highlightInfo.sq[1].x = toX;
\r
10574 highlightInfo.sq[1].y = toY;
\r
10578 ClearHighlights()
\r
10580 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10581 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10585 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10587 premoveHighlightInfo.sq[0].x = fromX;
\r
10588 premoveHighlightInfo.sq[0].y = fromY;
\r
10589 premoveHighlightInfo.sq[1].x = toX;
\r
10590 premoveHighlightInfo.sq[1].y = toY;
\r
10594 ClearPremoveHighlights()
\r
10596 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10597 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10601 ShutDownFrontEnd()
\r
10603 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10604 DeleteClipboardTempFiles();
\r
10610 if (IsIconic(hwndMain))
\r
10611 ShowWindow(hwndMain, SW_RESTORE);
\r
10613 SetActiveWindow(hwndMain);
\r
10617 * Prototypes for animation support routines
\r
10619 static void ScreenSquare(int column, int row, POINT * pt);
\r
10620 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10621 POINT frames[], int * nFrames);
\r
10625 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10626 { // [HGM] atomic: animate blast wave
\r
10628 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10629 explodeInfo.fromX = fromX;
\r
10630 explodeInfo.fromY = fromY;
\r
10631 explodeInfo.toX = toX;
\r
10632 explodeInfo.toY = toY;
\r
10633 for(i=1; i<nFrames; i++) {
\r
10634 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10635 DrawPosition(FALSE, NULL);
\r
10636 Sleep(appData.animSpeed);
\r
10638 explodeInfo.radius = 0;
\r
10639 DrawPosition(TRUE, NULL);
\r
10642 #define kFactor 4
\r
10645 AnimateMove(board, fromX, fromY, toX, toY)
\r
10652 ChessSquare piece;
\r
10653 POINT start, finish, mid;
\r
10654 POINT frames[kFactor * 2 + 1];
\r
10657 if (!appData.animate) return;
\r
10658 if (doingSizing) return;
\r
10659 if (fromY < 0 || fromX < 0) return;
\r
10660 piece = board[fromY][fromX];
\r
10661 if (piece >= EmptySquare) return;
\r
10663 ScreenSquare(fromX, fromY, &start);
\r
10664 ScreenSquare(toX, toY, &finish);
\r
10666 /* All pieces except knights move in straight line */
\r
10667 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10668 mid.x = start.x + (finish.x - start.x) / 2;
\r
10669 mid.y = start.y + (finish.y - start.y) / 2;
\r
10671 /* Knight: make diagonal movement then straight */
\r
10672 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10673 mid.x = start.x + (finish.x - start.x) / 2;
\r
10674 mid.y = finish.y;
\r
10676 mid.x = finish.x;
\r
10677 mid.y = start.y + (finish.y - start.y) / 2;
\r
10681 /* Don't use as many frames for very short moves */
\r
10682 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10683 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10685 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10687 animInfo.from.x = fromX;
\r
10688 animInfo.from.y = fromY;
\r
10689 animInfo.to.x = toX;
\r
10690 animInfo.to.y = toY;
\r
10691 animInfo.lastpos = start;
\r
10692 animInfo.piece = piece;
\r
10693 for (n = 0; n < nFrames; n++) {
\r
10694 animInfo.pos = frames[n];
\r
10695 DrawPosition(FALSE, NULL);
\r
10696 animInfo.lastpos = animInfo.pos;
\r
10697 Sleep(appData.animSpeed);
\r
10699 animInfo.pos = finish;
\r
10700 DrawPosition(FALSE, NULL);
\r
10701 animInfo.piece = EmptySquare;
\r
10702 if(gameInfo.variant == VariantAtomic &&
\r
10703 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10704 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10707 /* Convert board position to corner of screen rect and color */
\r
10710 ScreenSquare(column, row, pt)
\r
10711 int column; int row; POINT * pt;
\r
10714 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10715 pt->y = lineGap + row * (squareSize + lineGap);
\r
10717 pt->x = lineGap + column * (squareSize + lineGap);
\r
10718 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10722 /* Generate a series of frame coords from start->mid->finish.
\r
10723 The movement rate doubles until the half way point is
\r
10724 reached, then halves back down to the final destination,
\r
10725 which gives a nice slow in/out effect. The algorithmn
\r
10726 may seem to generate too many intermediates for short
\r
10727 moves, but remember that the purpose is to attract the
\r
10728 viewers attention to the piece about to be moved and
\r
10729 then to where it ends up. Too few frames would be less
\r
10733 Tween(start, mid, finish, factor, frames, nFrames)
\r
10734 POINT * start; POINT * mid;
\r
10735 POINT * finish; int factor;
\r
10736 POINT frames[]; int * nFrames;
\r
10738 int n, fraction = 1, count = 0;
\r
10740 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10741 for (n = 0; n < factor; n++)
\r
10743 for (n = 0; n < factor; n++) {
\r
10744 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10745 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10747 fraction = fraction / 2;
\r
10751 frames[count] = *mid;
\r
10754 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10756 for (n = 0; n < factor; n++) {
\r
10757 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10758 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10760 fraction = fraction * 2;
\r
10762 *nFrames = count;
\r
10766 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10768 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10770 EvalGraphSet( first, last, current, pvInfoList );
\r
10773 void SetProgramStats( FrontEndProgramStats * stats )
\r
10775 EngineOutputUpdate( stats );
\r