2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
291 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
292 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
293 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
294 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 BOOLEAN commentDialogUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 BOOLEAN engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
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
1501 /* Color name parser.
\r
1502 X version accepts X color names, but this one
\r
1503 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1505 ParseColorName(char *name)
\r
1507 int red, green, blue, count;
\r
1508 char buf[MSG_SIZ];
\r
1510 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1512 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1513 &red, &green, &blue);
\r
1516 sprintf(buf, "Can't parse color name %s", name);
\r
1517 DisplayError(buf, 0);
\r
1518 return RGB(0, 0, 0);
\r
1520 return PALETTERGB(red, green, blue);
\r
1524 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1526 char *e = argValue;
\r
1530 if (*e == 'b') eff |= CFE_BOLD;
\r
1531 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1532 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1533 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1534 else if (*e == '#' || isdigit(*e)) break;
\r
1538 *color = ParseColorName(e);
\r
1543 ParseBoardSize(char *name)
\r
1545 BoardSize bs = SizeTiny;
\r
1546 while (sizeInfo[bs].name != NULL) {
\r
1547 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1550 ExitArgError("Unrecognized board size value", name);
\r
1551 return bs; /* not reached */
\r
1556 StringGet(void *getClosure)
\r
1558 char **p = (char **) getClosure;
\r
1563 FileGet(void *getClosure)
\r
1566 FILE* f = (FILE*) getClosure;
\r
1569 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1576 /* Parse settings file named "name". If file found, return the
\r
1577 full name in fullname and return TRUE; else return FALSE */
\r
1579 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1583 int ok; char buf[MSG_SIZ];
\r
1585 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1586 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1587 sprintf(buf, "%s.ini", name);
\r
1588 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1591 f = fopen(fullname, "r");
\r
1593 ParseArgs(FileGet, f);
\r
1602 ParseArgs(GetFunc get, void *cl)
\r
1604 char argName[ARG_MAX];
\r
1605 char argValue[ARG_MAX];
\r
1606 ArgDescriptor *ad;
\r
1615 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1616 if (ch == NULLCHAR) break;
\r
1618 /* Comment to end of line */
\r
1620 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1622 } else if (ch == '/' || ch == '-') {
\r
1625 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1626 ch != '\n' && ch != '\t') {
\r
1632 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1633 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1635 if (ad->argName == NULL)
\r
1636 ExitArgError("Unrecognized argument", argName);
\r
1638 } else if (ch == '@') {
\r
1639 /* Indirection file */
\r
1640 ad = &argDescriptorIndirection;
\r
1643 /* Positional argument */
\r
1644 ad = &argDescriptors[posarg++];
\r
1645 strcpy(argName, ad->argName);
\r
1648 if (ad->argType == ArgTrue) {
\r
1649 *(Boolean *) ad->argLoc = TRUE;
\r
1652 if (ad->argType == ArgFalse) {
\r
1653 *(Boolean *) ad->argLoc = FALSE;
\r
1657 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1658 if (ch == NULLCHAR || ch == '\n') {
\r
1659 ExitArgError("No value provided for argument", argName);
\r
1663 // Quoting with { }. No characters have to (or can) be escaped.
\r
1664 // Thus the string cannot contain a '}' character.
\r
1684 } else if (ch == '\'' || ch == '"') {
\r
1685 // Quoting with ' ' or " ", with \ as escape character.
\r
1686 // Inconvenient for long strings that may contain Windows filenames.
\r
1703 if (ch == start) {
\r
1712 if (ad->argType == ArgFilename
\r
1713 || ad->argType == ArgSettingsFilename) {
\r
1719 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1743 for (i = 0; i < 3; i++) {
\r
1744 if (ch >= '0' && ch <= '7') {
\r
1745 octval = octval*8 + (ch - '0');
\r
1752 *q++ = (char) octval;
\r
1763 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1770 switch (ad->argType) {
\r
1772 *(int *) ad->argLoc = atoi(argValue);
\r
1776 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1780 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1784 *(int *) ad->argLoc = atoi(argValue);
\r
1785 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1789 *(float *) ad->argLoc = (float) atof(argValue);
\r
1794 *(char **) ad->argLoc = strdup(argValue);
\r
1797 case ArgSettingsFilename:
\r
1799 char fullname[MSG_SIZ];
\r
1800 if (ParseSettingsFile(argValue, fullname)) {
\r
1801 if (ad->argLoc != NULL) {
\r
1802 *(char **) ad->argLoc = strdup(fullname);
\r
1805 if (ad->argLoc != NULL) {
\r
1807 ExitArgError("Failed to open indirection file", argValue);
\r
1814 switch (argValue[0]) {
\r
1817 *(Boolean *) ad->argLoc = TRUE;
\r
1821 *(Boolean *) ad->argLoc = FALSE;
\r
1824 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1830 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1833 case ArgAttribs: {
\r
1834 ColorClass cc = (ColorClass)ad->argLoc;
\r
1835 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1839 case ArgBoardSize:
\r
1840 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1844 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1847 case ArgCommSettings:
\r
1848 ParseCommSettings(argValue, &dcb);
\r
1852 ExitArgError("Unrecognized argument", argValue);
\r
1861 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1863 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1864 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1867 lf->lfEscapement = 0;
\r
1868 lf->lfOrientation = 0;
\r
1869 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1870 lf->lfItalic = mfp->italic;
\r
1871 lf->lfUnderline = mfp->underline;
\r
1872 lf->lfStrikeOut = mfp->strikeout;
\r
1873 lf->lfCharSet = DEFAULT_CHARSET;
\r
1874 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1875 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1876 lf->lfQuality = DEFAULT_QUALITY;
\r
1877 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1878 strcpy(lf->lfFaceName, mfp->faceName);
\r
1882 CreateFontInMF(MyFont *mf)
\r
1884 LFfromMFP(&mf->lf, &mf->mfp);
\r
1885 if (mf->hf) DeleteObject(mf->hf);
\r
1886 mf->hf = CreateFontIndirect(&mf->lf);
\r
1890 SetDefaultTextAttribs()
\r
1893 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1894 ParseAttribs(&textAttribs[cc].color,
\r
1895 &textAttribs[cc].effects,
\r
1896 defaultTextAttribs[cc]);
\r
1901 SetDefaultSounds()
\r
1905 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1906 textAttribs[cc].sound.name = strdup("");
\r
1907 textAttribs[cc].sound.data = NULL;
\r
1909 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1910 sounds[sc].name = strdup("");
\r
1911 sounds[sc].data = NULL;
\r
1913 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1921 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1922 MyLoadSound(&textAttribs[cc].sound);
\r
1924 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1925 MyLoadSound(&sounds[sc]);
\r
1930 InitAppData(LPSTR lpCmdLine)
\r
1933 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1936 programName = szAppName;
\r
1938 /* Initialize to defaults */
\r
1939 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1940 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1941 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1942 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1943 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1944 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1945 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1946 SetDefaultTextAttribs();
\r
1947 SetDefaultSounds();
\r
1948 appData.movesPerSession = MOVES_PER_SESSION;
\r
1949 appData.initString = INIT_STRING;
\r
1950 appData.secondInitString = INIT_STRING;
\r
1951 appData.firstComputerString = COMPUTER_STRING;
\r
1952 appData.secondComputerString = COMPUTER_STRING;
\r
1953 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1954 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1955 appData.firstPlaysBlack = FALSE;
\r
1956 appData.noChessProgram = FALSE;
\r
1957 chessProgram = FALSE;
\r
1958 appData.firstHost = FIRST_HOST;
\r
1959 appData.secondHost = SECOND_HOST;
\r
1960 appData.firstDirectory = FIRST_DIRECTORY;
\r
1961 appData.secondDirectory = SECOND_DIRECTORY;
\r
1962 appData.bitmapDirectory = "";
\r
1963 appData.remoteShell = REMOTE_SHELL;
\r
1964 appData.remoteUser = "";
\r
1965 appData.timeDelay = TIME_DELAY;
\r
1966 appData.timeControl = TIME_CONTROL;
\r
1967 appData.timeIncrement = TIME_INCREMENT;
\r
1968 appData.icsActive = FALSE;
\r
1969 appData.icsHost = "";
\r
1970 appData.icsPort = ICS_PORT;
\r
1971 appData.icsCommPort = ICS_COMM_PORT;
\r
1972 appData.icsLogon = ICS_LOGON;
\r
1973 appData.icsHelper = "";
\r
1974 appData.useTelnet = FALSE;
\r
1975 appData.telnetProgram = TELNET_PROGRAM;
\r
1976 appData.gateway = "";
\r
1977 appData.loadGameFile = "";
\r
1978 appData.loadGameIndex = 0;
\r
1979 appData.saveGameFile = "";
\r
1980 appData.autoSaveGames = FALSE;
\r
1981 appData.loadPositionFile = "";
\r
1982 appData.loadPositionIndex = 1;
\r
1983 appData.savePositionFile = "";
\r
1984 appData.matchMode = FALSE;
\r
1985 appData.matchGames = 0;
\r
1986 appData.monoMode = FALSE;
\r
1987 appData.debugMode = FALSE;
\r
1988 appData.clockMode = TRUE;
\r
1989 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1990 appData.Iconic = FALSE; /*unused*/
\r
1991 appData.searchTime = "";
\r
1992 appData.searchDepth = 0;
\r
1993 appData.showCoords = FALSE;
\r
1994 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1995 appData.autoCallFlag = FALSE;
\r
1996 appData.flipView = FALSE;
\r
1997 appData.autoFlipView = TRUE;
\r
1998 appData.cmailGameName = "";
\r
1999 appData.alwaysPromoteToQueen = FALSE;
\r
2000 appData.oldSaveStyle = FALSE;
\r
2001 appData.quietPlay = FALSE;
\r
2002 appData.showThinking = FALSE;
\r
2003 appData.ponderNextMove = TRUE;
\r
2004 appData.periodicUpdates = TRUE;
\r
2005 appData.popupExitMessage = TRUE;
\r
2006 appData.popupMoveErrors = FALSE;
\r
2007 appData.autoObserve = FALSE;
\r
2008 appData.autoComment = FALSE;
\r
2009 appData.animate = TRUE;
\r
2010 appData.animSpeed = 10;
\r
2011 appData.animateDragging = TRUE;
\r
2012 appData.highlightLastMove = TRUE;
\r
2013 appData.getMoveList = TRUE;
\r
2014 appData.testLegality = TRUE;
\r
2015 appData.premove = TRUE;
\r
2016 appData.premoveWhite = FALSE;
\r
2017 appData.premoveWhiteText = "";
\r
2018 appData.premoveBlack = FALSE;
\r
2019 appData.premoveBlackText = "";
\r
2020 appData.icsAlarm = TRUE;
\r
2021 appData.icsAlarmTime = 5000;
\r
2022 appData.autoRaiseBoard = TRUE;
\r
2023 appData.localLineEditing = TRUE;
\r
2024 appData.colorize = TRUE;
\r
2025 appData.reuseFirst = TRUE;
\r
2026 appData.reuseSecond = TRUE;
\r
2027 appData.blindfold = FALSE;
\r
2028 appData.icsEngineAnalyze = FALSE;
\r
2029 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2030 dcb.DCBlength = sizeof(DCB);
\r
2031 dcb.BaudRate = 9600;
\r
2032 dcb.fBinary = TRUE;
\r
2033 dcb.fParity = FALSE;
\r
2034 dcb.fOutxCtsFlow = FALSE;
\r
2035 dcb.fOutxDsrFlow = FALSE;
\r
2036 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2037 dcb.fDsrSensitivity = FALSE;
\r
2038 dcb.fTXContinueOnXoff = TRUE;
\r
2039 dcb.fOutX = FALSE;
\r
2041 dcb.fNull = FALSE;
\r
2042 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2043 dcb.fAbortOnError = FALSE;
\r
2045 dcb.Parity = SPACEPARITY;
\r
2046 dcb.StopBits = ONESTOPBIT;
\r
2047 settingsFileName = SETTINGS_FILE;
\r
2048 saveSettingsOnExit = TRUE;
\r
2049 boardX = CW_USEDEFAULT;
\r
2050 boardY = CW_USEDEFAULT;
\r
2051 analysisX = CW_USEDEFAULT;
\r
2052 analysisY = CW_USEDEFAULT;
\r
2053 analysisW = CW_USEDEFAULT;
\r
2054 analysisH = CW_USEDEFAULT;
\r
2055 commentX = CW_USEDEFAULT;
\r
2056 commentY = CW_USEDEFAULT;
\r
2057 commentW = CW_USEDEFAULT;
\r
2058 commentH = CW_USEDEFAULT;
\r
2059 editTagsX = CW_USEDEFAULT;
\r
2060 editTagsY = CW_USEDEFAULT;
\r
2061 editTagsW = CW_USEDEFAULT;
\r
2062 editTagsH = CW_USEDEFAULT;
\r
2063 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2064 icsNames = ICS_NAMES;
\r
2065 firstChessProgramNames = FCP_NAMES;
\r
2066 secondChessProgramNames = SCP_NAMES;
\r
2067 appData.initialMode = "";
\r
2068 appData.variant = "normal";
\r
2069 appData.firstProtocolVersion = PROTOVER;
\r
2070 appData.secondProtocolVersion = PROTOVER;
\r
2071 appData.showButtonBar = TRUE;
\r
2073 /* [AS] New properties (see comments in header file) */
\r
2074 appData.firstScoreIsAbsolute = FALSE;
\r
2075 appData.secondScoreIsAbsolute = FALSE;
\r
2076 appData.saveExtendedInfoInPGN = FALSE;
\r
2077 appData.hideThinkingFromHuman = FALSE;
\r
2078 appData.liteBackTextureFile = "";
\r
2079 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2080 appData.darkBackTextureFile = "";
\r
2081 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2082 appData.renderPiecesWithFont = "";
\r
2083 appData.fontToPieceTable = "";
\r
2084 appData.fontBackColorWhite = 0;
\r
2085 appData.fontForeColorWhite = 0;
\r
2086 appData.fontBackColorBlack = 0;
\r
2087 appData.fontForeColorBlack = 0;
\r
2088 appData.fontPieceSize = 80;
\r
2089 appData.overrideLineGap = 1;
\r
2090 appData.adjudicateLossThreshold = 0;
\r
2091 appData.delayBeforeQuit = 0;
\r
2092 appData.delayAfterQuit = 0;
\r
2093 appData.nameOfDebugFile = "winboard.debug";
\r
2094 appData.pgnEventHeader = "Computer Chess Game";
\r
2095 appData.defaultFrcPosition = -1;
\r
2096 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2097 appData.saveOutOfBookInfo = TRUE;
\r
2098 appData.showEvalInMoveHistory = TRUE;
\r
2099 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2100 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2101 appData.highlightMoveWithArrow = FALSE;
\r
2102 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2103 appData.useStickyWindows = TRUE;
\r
2104 appData.adjudicateDrawMoves = 0;
\r
2105 appData.autoDisplayComment = TRUE;
\r
2106 appData.autoDisplayTags = TRUE;
\r
2107 appData.firstIsUCI = FALSE;
\r
2108 appData.secondIsUCI = FALSE;
\r
2109 appData.firstHasOwnBookUCI = TRUE;
\r
2110 appData.secondHasOwnBookUCI = TRUE;
\r
2111 appData.polyglotDir = "";
\r
2112 appData.usePolyglotBook = FALSE;
\r
2113 appData.polyglotBook = "";
\r
2114 appData.defaultHashSize = 64;
\r
2115 appData.defaultCacheSizeEGTB = 4;
\r
2116 appData.defaultPathEGTB = "c:\\egtb";
\r
2117 appData.firstOptions = "";
\r
2118 appData.secondOptions = "";
\r
2120 InitWindowPlacement( &wpGameList );
\r
2121 InitWindowPlacement( &wpMoveHistory );
\r
2122 InitWindowPlacement( &wpEvalGraph );
\r
2123 InitWindowPlacement( &wpEngineOutput );
\r
2124 InitWindowPlacement( &wpConsole );
\r
2126 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2127 appData.NrFiles = -1;
\r
2128 appData.NrRanks = -1;
\r
2129 appData.holdingsSize = -1;
\r
2130 appData.testClaims = FALSE;
\r
2131 appData.checkMates = FALSE;
\r
2132 appData.materialDraws= FALSE;
\r
2133 appData.trivialDraws = FALSE;
\r
2134 appData.ruleMoves = 51;
\r
2135 appData.drawRepeats = 6;
\r
2136 appData.matchPause = 10000;
\r
2137 appData.alphaRank = FALSE;
\r
2138 appData.allWhite = FALSE;
\r
2139 appData.upsideDown = FALSE;
\r
2140 appData.serverPause = 15;
\r
2141 appData.serverMovesName = NULL;
\r
2142 appData.suppressLoadMoves = FALSE;
\r
2143 appData.firstTimeOdds = 1;
\r
2144 appData.secondTimeOdds = 1;
\r
2145 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2146 appData.secondAccumulateTC = 1;
\r
2147 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2148 appData.secondNPS = -1;
\r
2149 appData.engineComments = 1;
\r
2150 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2151 appData.egtFormats = "";
\r
2154 appData.zippyTalk = ZIPPY_TALK;
\r
2155 appData.zippyPlay = ZIPPY_PLAY;
\r
2156 appData.zippyLines = ZIPPY_LINES;
\r
2157 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2158 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2159 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2160 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2161 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2162 appData.zippyUseI = ZIPPY_USE_I;
\r
2163 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2164 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2165 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2166 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2167 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2168 appData.zippyAbort = ZIPPY_ABORT;
\r
2169 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2170 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2171 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2174 /* Point font array elements to structures and
\r
2175 parse default font names */
\r
2176 for (i=0; i<NUM_FONTS; i++) {
\r
2177 for (j=0; j<NUM_SIZES; j++) {
\r
2178 font[j][i] = &fontRec[j][i];
\r
2179 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2183 /* Parse default settings file if any */
\r
2184 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2185 settingsFileName = strdup(buf);
\r
2188 /* Parse command line */
\r
2189 ParseArgs(StringGet, &lpCmdLine);
\r
2191 /* [HGM] make sure board size is acceptable */
\r
2192 if(appData.NrFiles > BOARD_SIZE ||
\r
2193 appData.NrRanks > BOARD_SIZE )
\r
2194 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2196 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2197 * with options from the command line, we now make an even higher priority
\r
2198 * overrule by WB options attached to the engine command line. This so that
\r
2199 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2202 if(appData.firstChessProgram != NULL) {
\r
2203 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2204 static char *f = "first";
\r
2205 char buf[MSG_SIZ], *q = buf;
\r
2206 if(p != NULL) { // engine command line contains WinBoard options
\r
2207 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2208 ParseArgs(StringGet, &q);
\r
2209 p[-1] = 0; // cut them offengine command line
\r
2212 // now do same for second chess program
\r
2213 if(appData.secondChessProgram != NULL) {
\r
2214 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2215 static char *s = "second";
\r
2216 char buf[MSG_SIZ], *q = buf;
\r
2217 if(p != NULL) { // engine command line contains WinBoard options
\r
2218 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2219 ParseArgs(StringGet, &q);
\r
2220 p[-1] = 0; // cut them offengine command line
\r
2225 /* Propagate options that affect others */
\r
2226 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2227 if (appData.icsActive || appData.noChessProgram) {
\r
2228 chessProgram = FALSE; /* not local chess program mode */
\r
2231 /* Open startup dialog if needed */
\r
2232 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2233 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2234 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2235 *appData.secondChessProgram == NULLCHAR))) {
\r
2238 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2239 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2240 FreeProcInstance(lpProc);
\r
2243 /* Make sure save files land in the right (?) directory */
\r
2244 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.saveGameFile = strdup(buf);
\r
2247 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2248 appData.savePositionFile = strdup(buf);
\r
2251 /* Finish initialization for fonts and sounds */
\r
2252 for (i=0; i<NUM_FONTS; i++) {
\r
2253 for (j=0; j<NUM_SIZES; j++) {
\r
2254 CreateFontInMF(font[j][i]);
\r
2257 /* xboard, and older WinBoards, controlled the move sound with the
\r
2258 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2259 always turn the option on (so that the backend will call us),
\r
2260 then let the user turn the sound off by setting it to silence if
\r
2261 desired. To accommodate old winboard.ini files saved by old
\r
2262 versions of WinBoard, we also turn off the sound if the option
\r
2263 was initially set to false. */
\r
2264 if (!appData.ringBellAfterMoves) {
\r
2265 sounds[(int)SoundMove].name = strdup("");
\r
2266 appData.ringBellAfterMoves = TRUE;
\r
2268 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2269 SetCurrentDirectory(installDir);
\r
2271 SetCurrentDirectory(currDir);
\r
2273 p = icsTextMenuString;
\r
2274 if (p[0] == '@') {
\r
2275 FILE* f = fopen(p + 1, "r");
\r
2277 DisplayFatalError(p + 1, errno, 2);
\r
2280 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2282 buf[i] = NULLCHAR;
\r
2285 ParseIcsTextMenu(strdup(p));
\r
2292 HMENU hmenu = GetMenu(hwndMain);
\r
2294 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2295 MF_BYCOMMAND|((appData.icsActive &&
\r
2296 *appData.icsCommPort != NULLCHAR) ?
\r
2297 MF_ENABLED : MF_GRAYED));
\r
2298 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2299 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2300 MF_CHECKED : MF_UNCHECKED));
\r
2305 SaveSettings(char* name)
\r
2308 ArgDescriptor *ad;
\r
2309 WINDOWPLACEMENT wp;
\r
2310 char dir[MSG_SIZ];
\r
2312 if (!hwndMain) return;
\r
2314 GetCurrentDirectory(MSG_SIZ, dir);
\r
2315 SetCurrentDirectory(installDir);
\r
2316 f = fopen(name, "w");
\r
2317 SetCurrentDirectory(dir);
\r
2319 DisplayError(name, errno);
\r
2322 fprintf(f, ";\n");
\r
2323 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2324 fprintf(f, ";\n");
\r
2325 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2326 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2327 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2328 fprintf(f, ";\n");
\r
2330 wp.length = sizeof(WINDOWPLACEMENT);
\r
2331 GetWindowPlacement(hwndMain, &wp);
\r
2332 boardX = wp.rcNormalPosition.left;
\r
2333 boardY = wp.rcNormalPosition.top;
\r
2335 if (hwndConsole) {
\r
2336 GetWindowPlacement(hwndConsole, &wp);
\r
2337 wpConsole.x = wp.rcNormalPosition.left;
\r
2338 wpConsole.y = wp.rcNormalPosition.top;
\r
2339 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2340 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2343 if (analysisDialog) {
\r
2344 GetWindowPlacement(analysisDialog, &wp);
\r
2345 analysisX = wp.rcNormalPosition.left;
\r
2346 analysisY = wp.rcNormalPosition.top;
\r
2347 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2348 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2351 if (commentDialog) {
\r
2352 GetWindowPlacement(commentDialog, &wp);
\r
2353 commentX = wp.rcNormalPosition.left;
\r
2354 commentY = wp.rcNormalPosition.top;
\r
2355 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2356 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2359 if (editTagsDialog) {
\r
2360 GetWindowPlacement(editTagsDialog, &wp);
\r
2361 editTagsX = wp.rcNormalPosition.left;
\r
2362 editTagsY = wp.rcNormalPosition.top;
\r
2363 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2364 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2367 if (gameListDialog) {
\r
2368 GetWindowPlacement(gameListDialog, &wp);
\r
2369 wpGameList.x = wp.rcNormalPosition.left;
\r
2370 wpGameList.y = wp.rcNormalPosition.top;
\r
2371 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2372 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2375 /* [AS] Move history */
\r
2376 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2378 if( moveHistoryDialog ) {
\r
2379 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2380 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2381 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2382 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2383 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2386 /* [AS] Eval graph */
\r
2387 wpEvalGraph.visible = EvalGraphIsUp();
\r
2389 if( evalGraphDialog ) {
\r
2390 GetWindowPlacement(evalGraphDialog, &wp);
\r
2391 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2392 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2393 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2394 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2397 /* [AS] Engine output */
\r
2398 wpEngineOutput.visible = EngineOutputIsUp();
\r
2400 if( engineOutputDialog ) {
\r
2401 GetWindowPlacement(engineOutputDialog, &wp);
\r
2402 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2403 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2404 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2405 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2408 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2409 if (!ad->save) continue;
\r
2410 switch (ad->argType) {
\r
2413 char *p = *(char **)ad->argLoc;
\r
2414 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2415 /* Quote multiline values or \-containing values
\r
2416 with { } if possible */
\r
2417 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2419 /* Else quote with " " */
\r
2420 fprintf(f, "/%s=\"", ad->argName);
\r
2422 if (*p == '\n') fprintf(f, "\n");
\r
2423 else if (*p == '\r') fprintf(f, "\\r");
\r
2424 else if (*p == '\t') fprintf(f, "\\t");
\r
2425 else if (*p == '\b') fprintf(f, "\\b");
\r
2426 else if (*p == '\f') fprintf(f, "\\f");
\r
2427 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2428 else if (*p == '\"') fprintf(f, "\\\"");
\r
2429 else if (*p == '\\') fprintf(f, "\\\\");
\r
2433 fprintf(f, "\"\n");
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2445 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2448 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2451 fprintf(f, "/%s=%s\n", ad->argName,
\r
2452 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2455 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2458 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2462 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2463 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2464 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2469 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2470 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2471 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2472 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2473 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2474 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2475 (ta->effects) ? " " : "",
\r
2476 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2480 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2481 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2483 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2486 case ArgBoardSize:
\r
2487 fprintf(f, "/%s=%s\n", ad->argName,
\r
2488 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2493 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2494 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2495 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2496 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2497 ad->argName, mfp->faceName, mfp->pointSize,
\r
2498 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2499 mfp->bold ? "b" : "",
\r
2500 mfp->italic ? "i" : "",
\r
2501 mfp->underline ? "u" : "",
\r
2502 mfp->strikeout ? "s" : "");
\r
2506 case ArgCommSettings:
\r
2507 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2509 case ArgSettingsFilename: ;
\r
2517 /*---------------------------------------------------------------------------*\
\r
2519 * GDI board drawing routines
\r
2521 \*---------------------------------------------------------------------------*/
\r
2523 /* [AS] Draw square using background texture */
\r
2524 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2529 return; /* Should never happen! */
\r
2532 SetGraphicsMode( dst, GM_ADVANCED );
\r
2539 /* X reflection */
\r
2544 x.eDx = (FLOAT) dw + dx - 1;
\r
2547 SetWorldTransform( dst, &x );
\r
2550 /* Y reflection */
\r
2556 x.eDy = (FLOAT) dh + dy - 1;
\r
2558 SetWorldTransform( dst, &x );
\r
2566 x.eDx = (FLOAT) dx;
\r
2567 x.eDy = (FLOAT) dy;
\r
2570 SetWorldTransform( dst, &x );
\r
2574 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2582 SetWorldTransform( dst, &x );
\r
2584 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2587 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2589 PM_WP = (int) WhitePawn,
\r
2590 PM_WN = (int) WhiteKnight,
\r
2591 PM_WB = (int) WhiteBishop,
\r
2592 PM_WR = (int) WhiteRook,
\r
2593 PM_WQ = (int) WhiteQueen,
\r
2594 PM_WF = (int) WhiteFerz,
\r
2595 PM_WW = (int) WhiteWazir,
\r
2596 PM_WE = (int) WhiteAlfil,
\r
2597 PM_WM = (int) WhiteMan,
\r
2598 PM_WO = (int) WhiteCannon,
\r
2599 PM_WU = (int) WhiteUnicorn,
\r
2600 PM_WH = (int) WhiteNightrider,
\r
2601 PM_WA = (int) WhiteAngel,
\r
2602 PM_WC = (int) WhiteMarshall,
\r
2603 PM_WAB = (int) WhiteCardinal,
\r
2604 PM_WD = (int) WhiteDragon,
\r
2605 PM_WL = (int) WhiteLance,
\r
2606 PM_WS = (int) WhiteCobra,
\r
2607 PM_WV = (int) WhiteFalcon,
\r
2608 PM_WSG = (int) WhiteSilver,
\r
2609 PM_WG = (int) WhiteGrasshopper,
\r
2610 PM_WK = (int) WhiteKing,
\r
2611 PM_BP = (int) BlackPawn,
\r
2612 PM_BN = (int) BlackKnight,
\r
2613 PM_BB = (int) BlackBishop,
\r
2614 PM_BR = (int) BlackRook,
\r
2615 PM_BQ = (int) BlackQueen,
\r
2616 PM_BF = (int) BlackFerz,
\r
2617 PM_BW = (int) BlackWazir,
\r
2618 PM_BE = (int) BlackAlfil,
\r
2619 PM_BM = (int) BlackMan,
\r
2620 PM_BO = (int) BlackCannon,
\r
2621 PM_BU = (int) BlackUnicorn,
\r
2622 PM_BH = (int) BlackNightrider,
\r
2623 PM_BA = (int) BlackAngel,
\r
2624 PM_BC = (int) BlackMarshall,
\r
2625 PM_BG = (int) BlackGrasshopper,
\r
2626 PM_BAB = (int) BlackCardinal,
\r
2627 PM_BD = (int) BlackDragon,
\r
2628 PM_BL = (int) BlackLance,
\r
2629 PM_BS = (int) BlackCobra,
\r
2630 PM_BV = (int) BlackFalcon,
\r
2631 PM_BSG = (int) BlackSilver,
\r
2632 PM_BK = (int) BlackKing
\r
2635 static HFONT hPieceFont = NULL;
\r
2636 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2637 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2638 static int fontBitmapSquareSize = 0;
\r
2639 static char pieceToFontChar[(int) EmptySquare] =
\r
2640 { 'p', 'n', 'b', 'r', 'q',
\r
2641 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2642 'k', 'o', 'm', 'v', 't', 'w',
\r
2643 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2646 extern BOOL SetCharTable( char *table, const char * map );
\r
2647 /* [HGM] moved to backend.c */
\r
2649 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2652 BYTE r1 = GetRValue( color );
\r
2653 BYTE g1 = GetGValue( color );
\r
2654 BYTE b1 = GetBValue( color );
\r
2660 /* Create a uniform background first */
\r
2661 hbrush = CreateSolidBrush( color );
\r
2662 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2663 FillRect( hdc, &rc, hbrush );
\r
2664 DeleteObject( hbrush );
\r
2667 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2668 int steps = squareSize / 2;
\r
2671 for( i=0; i<steps; i++ ) {
\r
2672 BYTE r = r1 - (r1-r2) * i / steps;
\r
2673 BYTE g = g1 - (g1-g2) * i / steps;
\r
2674 BYTE b = b1 - (b1-b2) * i / steps;
\r
2676 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2677 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2678 FillRect( hdc, &rc, hbrush );
\r
2679 DeleteObject(hbrush);
\r
2682 else if( mode == 2 ) {
\r
2683 /* Diagonal gradient, good more or less for every piece */
\r
2684 POINT triangle[3];
\r
2685 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2686 HBRUSH hbrush_old;
\r
2687 int steps = squareSize;
\r
2690 triangle[0].x = squareSize - steps;
\r
2691 triangle[0].y = squareSize;
\r
2692 triangle[1].x = squareSize;
\r
2693 triangle[1].y = squareSize;
\r
2694 triangle[2].x = squareSize;
\r
2695 triangle[2].y = squareSize - steps;
\r
2697 for( i=0; i<steps; i++ ) {
\r
2698 BYTE r = r1 - (r1-r2) * i / steps;
\r
2699 BYTE g = g1 - (g1-g2) * i / steps;
\r
2700 BYTE b = b1 - (b1-b2) * i / steps;
\r
2702 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2703 hbrush_old = SelectObject( hdc, hbrush );
\r
2704 Polygon( hdc, triangle, 3 );
\r
2705 SelectObject( hdc, hbrush_old );
\r
2706 DeleteObject(hbrush);
\r
2711 SelectObject( hdc, hpen );
\r
2716 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2717 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2718 piece: follow the steps as explained below.
\r
2720 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2724 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2728 int backColor = whitePieceColor;
\r
2729 int foreColor = blackPieceColor;
\r
2731 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2732 backColor = appData.fontBackColorWhite;
\r
2733 foreColor = appData.fontForeColorWhite;
\r
2735 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2736 backColor = appData.fontBackColorBlack;
\r
2737 foreColor = appData.fontForeColorBlack;
\r
2741 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2743 hbm_old = SelectObject( hdc, hbm );
\r
2747 rc.right = squareSize;
\r
2748 rc.bottom = squareSize;
\r
2750 /* Step 1: background is now black */
\r
2751 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2753 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2755 pt.x = (squareSize - sz.cx) / 2;
\r
2756 pt.y = (squareSize - sz.cy) / 2;
\r
2758 SetBkMode( hdc, TRANSPARENT );
\r
2759 SetTextColor( hdc, chroma );
\r
2760 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2761 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2763 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2764 /* Step 3: the area outside the piece is filled with white */
\r
2765 // FloodFill( hdc, 0, 0, chroma );
\r
2766 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2767 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2768 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2769 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2770 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2772 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2773 but if the start point is not inside the piece we're lost!
\r
2774 There should be a better way to do this... if we could create a region or path
\r
2775 from the fill operation we would be fine for example.
\r
2777 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2778 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2780 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2781 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2782 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2784 SelectObject( dc2, bm2 );
\r
2785 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2786 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2787 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2788 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2792 DeleteObject( bm2 );
\r
2795 SetTextColor( hdc, 0 );
\r
2797 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2798 draw the piece again in black for safety.
\r
2800 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2802 SelectObject( hdc, hbm_old );
\r
2804 if( hPieceMask[index] != NULL ) {
\r
2805 DeleteObject( hPieceMask[index] );
\r
2808 hPieceMask[index] = hbm;
\r
2811 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2813 SelectObject( hdc, hbm );
\r
2816 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2817 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2818 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2820 SelectObject( dc1, hPieceMask[index] );
\r
2821 SelectObject( dc2, bm2 );
\r
2822 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2823 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2826 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2827 the piece background and deletes (makes transparent) the rest.
\r
2828 Thanks to that mask, we are free to paint the background with the greates
\r
2829 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2830 We use this, to make gradients and give the pieces a "roundish" look.
\r
2832 SetPieceBackground( hdc, backColor, 2 );
\r
2833 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2837 DeleteObject( bm2 );
\r
2840 SetTextColor( hdc, foreColor );
\r
2841 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2843 SelectObject( hdc, hbm_old );
\r
2845 if( hPieceFace[index] != NULL ) {
\r
2846 DeleteObject( hPieceFace[index] );
\r
2849 hPieceFace[index] = hbm;
\r
2852 static int TranslatePieceToFontPiece( int piece )
\r
2882 case BlackMarshall:
\r
2886 case BlackNightrider:
\r
2892 case BlackUnicorn:
\r
2896 case BlackGrasshopper:
\r
2908 case BlackCardinal:
\r
2915 case WhiteMarshall:
\r
2919 case WhiteNightrider:
\r
2925 case WhiteUnicorn:
\r
2929 case WhiteGrasshopper:
\r
2941 case WhiteCardinal:
\r
2950 void CreatePiecesFromFont()
\r
2953 HDC hdc_window = NULL;
\r
2959 if( fontBitmapSquareSize < 0 ) {
\r
2960 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2964 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2965 fontBitmapSquareSize = -1;
\r
2969 if( fontBitmapSquareSize != squareSize ) {
\r
2970 hdc_window = GetDC( hwndMain );
\r
2971 hdc = CreateCompatibleDC( hdc_window );
\r
2973 if( hPieceFont != NULL ) {
\r
2974 DeleteObject( hPieceFont );
\r
2977 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2978 hPieceMask[i] = NULL;
\r
2979 hPieceFace[i] = NULL;
\r
2985 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2986 fontHeight = appData.fontPieceSize;
\r
2989 fontHeight = (fontHeight * squareSize) / 100;
\r
2991 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2993 lf.lfEscapement = 0;
\r
2994 lf.lfOrientation = 0;
\r
2995 lf.lfWeight = FW_NORMAL;
\r
2997 lf.lfUnderline = 0;
\r
2998 lf.lfStrikeOut = 0;
\r
2999 lf.lfCharSet = DEFAULT_CHARSET;
\r
3000 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3001 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3002 lf.lfQuality = PROOF_QUALITY;
\r
3003 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3004 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3005 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3007 hPieceFont = CreateFontIndirect( &lf );
\r
3009 if( hPieceFont == NULL ) {
\r
3010 fontBitmapSquareSize = -2;
\r
3013 /* Setup font-to-piece character table */
\r
3014 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3015 /* No (or wrong) global settings, try to detect the font */
\r
3016 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3018 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3020 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3021 /* DiagramTT* family */
\r
3022 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3024 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3025 /* Fairy symbols */
\r
3026 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3028 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3029 /* Good Companion (Some characters get warped as literal :-( */
\r
3030 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3031 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3032 SetCharTable(pieceToFontChar, s);
\r
3035 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3036 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3040 /* Create bitmaps */
\r
3041 hfont_old = SelectObject( hdc, hPieceFont );
\r
3042 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3043 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3046 SelectObject( hdc, hfont_old );
\r
3048 fontBitmapSquareSize = squareSize;
\r
3052 if( hdc != NULL ) {
\r
3056 if( hdc_window != NULL ) {
\r
3057 ReleaseDC( hwndMain, hdc_window );
\r
3062 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3066 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3067 if (gameInfo.event &&
\r
3068 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3069 strcmp(name, "k80s") == 0) {
\r
3070 strcpy(name, "tim");
\r
3072 return LoadBitmap(hinst, name);
\r
3076 /* Insert a color into the program's logical palette
\r
3077 structure. This code assumes the given color is
\r
3078 the result of the RGB or PALETTERGB macro, and it
\r
3079 knows how those macros work (which is documented).
\r
3082 InsertInPalette(COLORREF color)
\r
3084 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3086 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3087 DisplayFatalError("Too many colors", 0, 1);
\r
3088 pLogPal->palNumEntries--;
\r
3092 pe->peFlags = (char) 0;
\r
3093 pe->peRed = (char) (0xFF & color);
\r
3094 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3095 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3101 InitDrawingColors()
\r
3103 if (pLogPal == NULL) {
\r
3104 /* Allocate enough memory for a logical palette with
\r
3105 * PALETTESIZE entries and set the size and version fields
\r
3106 * of the logical palette structure.
\r
3108 pLogPal = (NPLOGPALETTE)
\r
3109 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3110 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3111 pLogPal->palVersion = 0x300;
\r
3113 pLogPal->palNumEntries = 0;
\r
3115 InsertInPalette(lightSquareColor);
\r
3116 InsertInPalette(darkSquareColor);
\r
3117 InsertInPalette(whitePieceColor);
\r
3118 InsertInPalette(blackPieceColor);
\r
3119 InsertInPalette(highlightSquareColor);
\r
3120 InsertInPalette(premoveHighlightColor);
\r
3122 /* create a logical color palette according the information
\r
3123 * in the LOGPALETTE structure.
\r
3125 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3127 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3128 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3129 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3130 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3131 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3132 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3133 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3134 /* [AS] Force rendering of the font-based pieces */
\r
3135 if( fontBitmapSquareSize > 0 ) {
\r
3136 fontBitmapSquareSize = 0;
\r
3142 BoardWidth(int boardSize, int n)
\r
3143 { /* [HGM] argument n added to allow different width and height */
\r
3144 int lineGap = sizeInfo[boardSize].lineGap;
\r
3146 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3147 lineGap = appData.overrideLineGap;
\r
3150 return (n + 1) * lineGap +
\r
3151 n * sizeInfo[boardSize].squareSize;
\r
3154 /* Respond to board resize by dragging edge */
\r
3156 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3158 BoardSize newSize = NUM_SIZES - 1;
\r
3159 static int recurse = 0;
\r
3160 if (IsIconic(hwndMain)) return;
\r
3161 if (recurse > 0) return;
\r
3163 while (newSize > 0) {
\r
3164 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3165 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3166 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3169 boardSize = newSize;
\r
3170 InitDrawingSizes(boardSize, flags);
\r
3177 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3179 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3180 ChessSquare piece;
\r
3181 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3183 SIZE clockSize, messageSize;
\r
3185 char buf[MSG_SIZ];
\r
3187 HMENU hmenu = GetMenu(hwndMain);
\r
3188 RECT crect, wrect, oldRect;
\r
3190 LOGBRUSH logbrush;
\r
3192 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3193 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3195 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3196 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3198 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3199 oldRect.top = boardY;
\r
3200 oldRect.right = boardX + winWidth;
\r
3201 oldRect.bottom = boardY + winHeight;
\r
3203 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3204 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3205 squareSize = sizeInfo[boardSize].squareSize;
\r
3206 lineGap = sizeInfo[boardSize].lineGap;
\r
3207 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3209 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3210 lineGap = appData.overrideLineGap;
\r
3213 if (tinyLayout != oldTinyLayout) {
\r
3214 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3216 style &= ~WS_SYSMENU;
\r
3217 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3218 "&Minimize\tCtrl+F4");
\r
3220 style |= WS_SYSMENU;
\r
3221 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3223 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3225 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3226 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3227 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3229 DrawMenuBar(hwndMain);
\r
3232 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3233 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3235 /* Get text area sizes */
\r
3236 hdc = GetDC(hwndMain);
\r
3237 if (appData.clockMode) {
\r
3238 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3240 sprintf(buf, "White");
\r
3242 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3243 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3244 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3245 str = "We only care about the height here";
\r
3246 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3247 SelectObject(hdc, oldFont);
\r
3248 ReleaseDC(hwndMain, hdc);
\r
3250 /* Compute where everything goes */
\r
3251 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3252 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3253 logoHeight = 2*clockSize.cy;
\r
3254 leftLogoRect.left = OUTER_MARGIN;
\r
3255 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3256 leftLogoRect.top = OUTER_MARGIN;
\r
3257 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3259 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3260 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3261 rightLogoRect.top = OUTER_MARGIN;
\r
3262 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3265 whiteRect.left = leftLogoRect.right;
\r
3266 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3267 whiteRect.top = OUTER_MARGIN;
\r
3268 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3270 blackRect.right = rightLogoRect.left;
\r
3271 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3272 blackRect.top = whiteRect.top;
\r
3273 blackRect.bottom = whiteRect.bottom;
\r
3275 whiteRect.left = OUTER_MARGIN;
\r
3276 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3277 whiteRect.top = OUTER_MARGIN;
\r
3278 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3280 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3281 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3282 blackRect.top = whiteRect.top;
\r
3283 blackRect.bottom = whiteRect.bottom;
\r
3286 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3287 if (appData.showButtonBar) {
\r
3288 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3289 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3291 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3293 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3294 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3296 boardRect.left = OUTER_MARGIN;
\r
3297 boardRect.right = boardRect.left + boardWidth;
\r
3298 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3299 boardRect.bottom = boardRect.top + boardHeight;
\r
3301 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3302 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3303 oldBoardSize = boardSize;
\r
3304 oldTinyLayout = tinyLayout;
\r
3305 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3306 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3307 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3308 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3309 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3310 winHeight = winH; // without disturbing window attachments
\r
3311 GetWindowRect(hwndMain, &wrect);
\r
3312 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3313 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3315 // [HGM] placement: let attached windows follow size change.
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3318 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3319 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3320 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3322 /* compensate if menu bar wrapped */
\r
3323 GetClientRect(hwndMain, &crect);
\r
3324 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3325 winHeight += offby;
\r
3327 case WMSZ_TOPLEFT:
\r
3328 SetWindowPos(hwndMain, NULL,
\r
3329 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3330 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3333 case WMSZ_TOPRIGHT:
\r
3335 SetWindowPos(hwndMain, NULL,
\r
3336 wrect.left, wrect.bottom - winHeight,
\r
3337 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3340 case WMSZ_BOTTOMLEFT:
\r
3342 SetWindowPos(hwndMain, NULL,
\r
3343 wrect.right - winWidth, wrect.top,
\r
3344 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3347 case WMSZ_BOTTOMRIGHT:
\r
3351 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3352 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3357 for (i = 0; i < N_BUTTONS; i++) {
\r
3358 if (buttonDesc[i].hwnd != NULL) {
\r
3359 DestroyWindow(buttonDesc[i].hwnd);
\r
3360 buttonDesc[i].hwnd = NULL;
\r
3362 if (appData.showButtonBar) {
\r
3363 buttonDesc[i].hwnd =
\r
3364 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3365 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3366 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3367 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3368 (HMENU) buttonDesc[i].id,
\r
3369 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3371 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3372 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3373 MAKELPARAM(FALSE, 0));
\r
3375 if (buttonDesc[i].id == IDM_Pause)
\r
3376 hwndPause = buttonDesc[i].hwnd;
\r
3377 buttonDesc[i].wndproc = (WNDPROC)
\r
3378 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3381 if (gridPen != NULL) DeleteObject(gridPen);
\r
3382 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3383 if (premovePen != NULL) DeleteObject(premovePen);
\r
3384 if (lineGap != 0) {
\r
3385 logbrush.lbStyle = BS_SOLID;
\r
3386 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3388 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3389 lineGap, &logbrush, 0, NULL);
\r
3390 logbrush.lbColor = highlightSquareColor;
\r
3392 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3393 lineGap, &logbrush, 0, NULL);
\r
3395 logbrush.lbColor = premoveHighlightColor;
\r
3397 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3398 lineGap, &logbrush, 0, NULL);
\r
3400 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3401 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3402 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3403 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3404 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3405 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3406 BOARD_WIDTH * (squareSize + lineGap);
\r
3407 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3409 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3410 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3411 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3412 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3413 lineGap / 2 + (i * (squareSize + lineGap));
\r
3414 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3415 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3416 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3420 /* [HGM] Licensing requirement */
\r
3422 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3425 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3427 GothicPopUp( "", VariantNormal);
\r
3430 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3432 /* Load piece bitmaps for this board size */
\r
3433 for (i=0; i<=2; i++) {
\r
3434 for (piece = WhitePawn;
\r
3435 (int) piece < (int) BlackPawn;
\r
3436 piece = (ChessSquare) ((int) piece + 1)) {
\r
3437 if (pieceBitmap[i][piece] != NULL)
\r
3438 DeleteObject(pieceBitmap[i][piece]);
\r
3442 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3443 // Orthodox Chess pieces
\r
3444 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3446 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3447 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3448 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3449 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3451 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3452 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3453 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3454 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3456 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3457 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3458 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3459 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3460 // in Shogi, Hijack the unused Queen for Lance
\r
3461 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3462 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3463 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3465 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3466 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3467 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3470 if(squareSize <= 72 && squareSize >= 33) {
\r
3471 /* A & C are available in most sizes now */
\r
3472 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3473 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3482 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3483 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3484 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3485 } else { // Smirf-like
\r
3486 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3487 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3488 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3490 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3491 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3492 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3493 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3494 } else { // WinBoard standard
\r
3495 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3496 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3497 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3502 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3503 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3515 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3530 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3534 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3535 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3544 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3545 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3546 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3562 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3563 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3564 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3565 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3566 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3567 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3568 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3569 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3570 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3571 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3572 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3573 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3574 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3575 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3576 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3580 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3581 /* special Shogi support in this size */
\r
3582 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3583 for (piece = WhitePawn;
\r
3584 (int) piece < (int) BlackPawn;
\r
3585 piece = (ChessSquare) ((int) piece + 1)) {
\r
3586 if (pieceBitmap[i][piece] != NULL)
\r
3587 DeleteObject(pieceBitmap[i][piece]);
\r
3590 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3601 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3602 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3603 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3604 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3615 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3616 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3617 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3618 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3629 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3630 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3631 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3637 PieceBitmap(ChessSquare p, int kind)
\r
3639 if ((int) p >= (int) BlackPawn)
\r
3640 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3642 return pieceBitmap[kind][(int) p];
\r
3645 /***************************************************************/
\r
3647 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3648 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3650 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3651 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3655 SquareToPos(int row, int column, int * x, int * y)
\r
3658 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3659 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3661 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3662 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3667 DrawCoordsOnDC(HDC hdc)
\r
3669 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
3670 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
3671 char str[2] = { NULLCHAR, NULLCHAR };
\r
3672 int oldMode, oldAlign, x, y, start, i;
\r
3676 if (!appData.showCoords)
\r
3679 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3681 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3682 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3683 oldAlign = GetTextAlign(hdc);
\r
3684 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3686 y = boardRect.top + lineGap;
\r
3687 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3689 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3690 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3691 str[0] = files[start + i];
\r
3692 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3693 y += squareSize + lineGap;
\r
3696 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3698 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3699 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3700 str[0] = ranks[start + i];
\r
3701 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3702 x += squareSize + lineGap;
\r
3705 SelectObject(hdc, oldBrush);
\r
3706 SetBkMode(hdc, oldMode);
\r
3707 SetTextAlign(hdc, oldAlign);
\r
3708 SelectObject(hdc, oldFont);
\r
3712 DrawGridOnDC(HDC hdc)
\r
3716 if (lineGap != 0) {
\r
3717 oldPen = SelectObject(hdc, gridPen);
\r
3718 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3719 SelectObject(hdc, oldPen);
\r
3723 #define HIGHLIGHT_PEN 0
\r
3724 #define PREMOVE_PEN 1
\r
3727 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3730 HPEN oldPen, hPen;
\r
3731 if (lineGap == 0) return;
\r
3733 x1 = boardRect.left +
\r
3734 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3735 y1 = boardRect.top +
\r
3736 lineGap/2 + y * (squareSize + lineGap);
\r
3738 x1 = boardRect.left +
\r
3739 lineGap/2 + x * (squareSize + lineGap);
\r
3740 y1 = boardRect.top +
\r
3741 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3743 hPen = pen ? premovePen : highlightPen;
\r
3744 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3745 MoveToEx(hdc, x1, y1, NULL);
\r
3746 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3747 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3748 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3749 LineTo(hdc, x1, y1);
\r
3750 SelectObject(hdc, oldPen);
\r
3754 DrawHighlightsOnDC(HDC hdc)
\r
3757 for (i=0; i<2; i++) {
\r
3758 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3759 DrawHighlightOnDC(hdc, TRUE,
\r
3760 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3763 for (i=0; i<2; i++) {
\r
3764 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3765 premoveHighlightInfo.sq[i].y >= 0) {
\r
3766 DrawHighlightOnDC(hdc, TRUE,
\r
3767 premoveHighlightInfo.sq[i].x,
\r
3768 premoveHighlightInfo.sq[i].y,
\r
3774 /* Note: sqcolor is used only in monoMode */
\r
3775 /* Note that this code is largely duplicated in woptions.c,
\r
3776 function DrawSampleSquare, so that needs to be updated too */
\r
3778 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3780 HBITMAP oldBitmap;
\r
3784 if (appData.blindfold) return;
\r
3786 /* [AS] Use font-based pieces if needed */
\r
3787 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3788 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3789 CreatePiecesFromFont();
\r
3791 if( fontBitmapSquareSize == squareSize ) {
\r
3792 int index = TranslatePieceToFontPiece(piece);
\r
3794 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3798 squareSize, squareSize,
\r
3803 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3807 squareSize, squareSize,
\r
3816 if (appData.monoMode) {
\r
3817 SelectObject(tmphdc, PieceBitmap(piece,
\r
3818 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3819 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3820 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3822 tmpSize = squareSize;
\r
3824 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3825 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3826 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3827 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3828 x += (squareSize - minorSize)>>1;
\r
3829 y += squareSize - minorSize - 2;
\r
3830 tmpSize = minorSize;
\r
3832 if (color || appData.allWhite ) {
\r
3833 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3835 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3836 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3837 if(appData.upsideDown && color==flipView)
\r
3838 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3840 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3841 /* Use black for outline of white pieces */
\r
3842 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3843 if(appData.upsideDown && color==flipView)
\r
3844 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3846 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3848 /* Use square color for details of black pieces */
\r
3849 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3850 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3851 if(appData.upsideDown && !flipView)
\r
3852 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3854 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3856 SelectObject(hdc, oldBrush);
\r
3857 SelectObject(tmphdc, oldBitmap);
\r
3861 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3862 int GetBackTextureMode( int algo )
\r
3864 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3868 case BACK_TEXTURE_MODE_PLAIN:
\r
3869 result = 1; /* Always use identity map */
\r
3871 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3872 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3880 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3881 to handle redraws cleanly (as random numbers would always be different).
\r
3883 VOID RebuildTextureSquareInfo()
\r
3893 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3895 if( liteBackTexture != NULL ) {
\r
3896 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3897 lite_w = bi.bmWidth;
\r
3898 lite_h = bi.bmHeight;
\r
3902 if( darkBackTexture != NULL ) {
\r
3903 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3904 dark_w = bi.bmWidth;
\r
3905 dark_h = bi.bmHeight;
\r
3909 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3910 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3911 if( (col + row) & 1 ) {
\r
3913 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3914 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3915 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3916 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3921 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3922 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3923 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3924 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3931 /* [AS] Arrow highlighting support */
\r
3933 static int A_WIDTH = 5; /* Width of arrow body */
\r
3935 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3936 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3938 static double Sqr( double x )
\r
3943 static int Round( double x )
\r
3945 return (int) (x + 0.5);
\r
3948 /* Draw an arrow between two points using current settings */
\r
3949 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3952 double dx, dy, j, k, x, y;
\r
3954 if( d_x == s_x ) {
\r
3955 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3957 arrow[0].x = s_x + A_WIDTH;
\r
3960 arrow[1].x = s_x + A_WIDTH;
\r
3961 arrow[1].y = d_y - h;
\r
3963 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3964 arrow[2].y = d_y - h;
\r
3969 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3970 arrow[4].y = d_y - h;
\r
3972 arrow[5].x = s_x - A_WIDTH;
\r
3973 arrow[5].y = d_y - h;
\r
3975 arrow[6].x = s_x - A_WIDTH;
\r
3978 else if( d_y == s_y ) {
\r
3979 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3982 arrow[0].y = s_y + A_WIDTH;
\r
3984 arrow[1].x = d_x - w;
\r
3985 arrow[1].y = s_y + A_WIDTH;
\r
3987 arrow[2].x = d_x - w;
\r
3988 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3993 arrow[4].x = d_x - w;
\r
3994 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3996 arrow[5].x = d_x - w;
\r
3997 arrow[5].y = s_y - A_WIDTH;
\r
4000 arrow[6].y = s_y - A_WIDTH;
\r
4003 /* [AS] Needed a lot of paper for this! :-) */
\r
4004 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4005 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4007 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4009 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4014 arrow[0].x = Round(x - j);
\r
4015 arrow[0].y = Round(y + j*dx);
\r
4017 arrow[1].x = Round(x + j);
\r
4018 arrow[1].y = Round(y - j*dx);
\r
4021 x = (double) d_x - k;
\r
4022 y = (double) d_y - k*dy;
\r
4025 x = (double) d_x + k;
\r
4026 y = (double) d_y + k*dy;
\r
4029 arrow[2].x = Round(x + j);
\r
4030 arrow[2].y = Round(y - j*dx);
\r
4032 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4033 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4038 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4039 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4041 arrow[6].x = Round(x - j);
\r
4042 arrow[6].y = Round(y + j*dx);
\r
4045 Polygon( hdc, arrow, 7 );
\r
4048 /* [AS] Draw an arrow between two squares */
\r
4049 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4051 int s_x, s_y, d_x, d_y;
\r
4058 if( s_col == d_col && s_row == d_row ) {
\r
4062 /* Get source and destination points */
\r
4063 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4064 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4067 d_y += squareSize / 4;
\r
4069 else if( d_y < s_y ) {
\r
4070 d_y += 3 * squareSize / 4;
\r
4073 d_y += squareSize / 2;
\r
4077 d_x += squareSize / 4;
\r
4079 else if( d_x < s_x ) {
\r
4080 d_x += 3 * squareSize / 4;
\r
4083 d_x += squareSize / 2;
\r
4086 s_x += squareSize / 2;
\r
4087 s_y += squareSize / 2;
\r
4089 /* Adjust width */
\r
4090 A_WIDTH = squareSize / 14;
\r
4093 stLB.lbStyle = BS_SOLID;
\r
4094 stLB.lbColor = appData.highlightArrowColor;
\r
4097 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4098 holdpen = SelectObject( hdc, hpen );
\r
4099 hbrush = CreateBrushIndirect( &stLB );
\r
4100 holdbrush = SelectObject( hdc, hbrush );
\r
4102 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4104 SelectObject( hdc, holdpen );
\r
4105 SelectObject( hdc, holdbrush );
\r
4106 DeleteObject( hpen );
\r
4107 DeleteObject( hbrush );
\r
4110 BOOL HasHighlightInfo()
\r
4112 BOOL result = FALSE;
\r
4114 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4115 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4123 BOOL IsDrawArrowEnabled()
\r
4125 BOOL result = FALSE;
\r
4127 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4134 VOID DrawArrowHighlight( HDC hdc )
\r
4136 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4137 DrawArrowBetweenSquares( hdc,
\r
4138 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4139 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4143 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4145 HRGN result = NULL;
\r
4147 if( HasHighlightInfo() ) {
\r
4148 int x1, y1, x2, y2;
\r
4149 int sx, sy, dx, dy;
\r
4151 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4152 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4154 sx = MIN( x1, x2 );
\r
4155 sy = MIN( y1, y2 );
\r
4156 dx = MAX( x1, x2 ) + squareSize;
\r
4157 dy = MAX( y1, y2 ) + squareSize;
\r
4159 result = CreateRectRgn( sx, sy, dx, dy );
\r
4166 Warning: this function modifies the behavior of several other functions.
\r
4168 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4169 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4170 repaint is scattered all over the place, which is not good for features such as
\r
4171 "arrow highlighting" that require a full repaint of the board.
\r
4173 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4174 user interaction, when speed is not so important) but especially to avoid errors
\r
4175 in the displayed graphics.
\r
4177 In such patched places, I always try refer to this function so there is a single
\r
4178 place to maintain knowledge.
\r
4180 To restore the original behavior, just return FALSE unconditionally.
\r
4182 BOOL IsFullRepaintPreferrable()
\r
4184 BOOL result = FALSE;
\r
4186 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4187 /* Arrow may appear on the board */
\r
4195 This function is called by DrawPosition to know whether a full repaint must
\r
4198 Only DrawPosition may directly call this function, which makes use of
\r
4199 some state information. Other function should call DrawPosition specifying
\r
4200 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4202 BOOL DrawPositionNeedsFullRepaint()
\r
4204 BOOL result = FALSE;
\r
4207 Probably a slightly better policy would be to trigger a full repaint
\r
4208 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4209 but animation is fast enough that it's difficult to notice.
\r
4211 if( animInfo.piece == EmptySquare ) {
\r
4212 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4221 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4223 int row, column, x, y, square_color, piece_color;
\r
4224 ChessSquare piece;
\r
4226 HDC texture_hdc = NULL;
\r
4228 /* [AS] Initialize background textures if needed */
\r
4229 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4230 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4231 if( backTextureSquareSize != squareSize
\r
4232 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4233 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4234 backTextureSquareSize = squareSize;
\r
4235 RebuildTextureSquareInfo();
\r
4238 texture_hdc = CreateCompatibleDC( hdc );
\r
4241 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4242 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4244 SquareToPos(row, column, &x, &y);
\r
4246 piece = board[row][column];
\r
4248 square_color = ((column + row) % 2) == 1;
\r
4249 if( gameInfo.variant == VariantXiangqi ) {
\r
4250 square_color = !InPalace(row, column);
\r
4251 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4252 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4254 piece_color = (int) piece < (int) BlackPawn;
\r
4257 /* [HGM] holdings file: light square or black */
\r
4258 if(column == BOARD_LEFT-2) {
\r
4259 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4262 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4266 if(column == BOARD_RGHT + 1 ) {
\r
4267 if( row < gameInfo.holdingsSize )
\r
4270 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4274 if(column == BOARD_LEFT-1 ) /* left align */
\r
4275 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4276 else if( column == BOARD_RGHT) /* right align */
\r
4277 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4279 if (appData.monoMode) {
\r
4280 if (piece == EmptySquare) {
\r
4281 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4282 square_color ? WHITENESS : BLACKNESS);
\r
4284 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4287 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4288 /* [AS] Draw the square using a texture bitmap */
\r
4289 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4290 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4291 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4294 squareSize, squareSize,
\r
4297 backTextureSquareInfo[r][c].mode,
\r
4298 backTextureSquareInfo[r][c].x,
\r
4299 backTextureSquareInfo[r][c].y );
\r
4301 SelectObject( texture_hdc, hbm );
\r
4303 if (piece != EmptySquare) {
\r
4304 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4308 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4310 oldBrush = SelectObject(hdc, brush );
\r
4311 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4312 SelectObject(hdc, oldBrush);
\r
4313 if (piece != EmptySquare)
\r
4314 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4319 if( texture_hdc != NULL ) {
\r
4320 DeleteDC( texture_hdc );
\r
4324 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4325 void fputDW(FILE *f, int x)
\r
4327 fputc(x & 255, f);
\r
4328 fputc(x>>8 & 255, f);
\r
4329 fputc(x>>16 & 255, f);
\r
4330 fputc(x>>24 & 255, f);
\r
4333 #define MAX_CLIPS 200 /* more than enough */
\r
4336 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4338 // HBITMAP bufferBitmap;
\r
4343 int w = 100, h = 50;
\r
4345 if(logo == NULL) return;
\r
4346 // GetClientRect(hwndMain, &Rect);
\r
4347 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4348 // Rect.bottom-Rect.top+1);
\r
4349 tmphdc = CreateCompatibleDC(hdc);
\r
4350 hbm = SelectObject(tmphdc, logo);
\r
4351 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4355 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4356 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4357 SelectObject(tmphdc, hbm);
\r
4362 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4364 static Board lastReq, lastDrawn;
\r
4365 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4366 static int lastDrawnFlipView = 0;
\r
4367 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4368 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4371 HBITMAP bufferBitmap;
\r
4372 HBITMAP oldBitmap;
\r
4374 HRGN clips[MAX_CLIPS];
\r
4375 ChessSquare dragged_piece = EmptySquare;
\r
4377 /* I'm undecided on this - this function figures out whether a full
\r
4378 * repaint is necessary on its own, so there's no real reason to have the
\r
4379 * caller tell it that. I think this can safely be set to FALSE - but
\r
4380 * if we trust the callers not to request full repaints unnessesarily, then
\r
4381 * we could skip some clipping work. In other words, only request a full
\r
4382 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4383 * gamestart and similar) --Hawk
\r
4385 Boolean fullrepaint = repaint;
\r
4387 if( DrawPositionNeedsFullRepaint() ) {
\r
4388 fullrepaint = TRUE;
\r
4391 if (board == NULL) {
\r
4392 if (!lastReqValid) {
\r
4397 CopyBoard(lastReq, board);
\r
4401 if (doingSizing) {
\r
4405 if (IsIconic(hwndMain)) {
\r
4409 if (hdc == NULL) {
\r
4410 hdc = GetDC(hwndMain);
\r
4411 if (!appData.monoMode) {
\r
4412 SelectPalette(hdc, hPal, FALSE);
\r
4413 RealizePalette(hdc);
\r
4417 releaseDC = FALSE;
\r
4420 /* Create some work-DCs */
\r
4421 hdcmem = CreateCompatibleDC(hdc);
\r
4422 tmphdc = CreateCompatibleDC(hdc);
\r
4424 /* If dragging is in progress, we temporarely remove the piece */
\r
4425 /* [HGM] or temporarily decrease count if stacked */
\r
4426 /* !! Moved to before board compare !! */
\r
4427 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4428 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4429 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4430 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4431 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4433 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4434 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4435 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4437 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4440 /* Figure out which squares need updating by comparing the
\r
4441 * newest board with the last drawn board and checking if
\r
4442 * flipping has changed.
\r
4444 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4445 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4446 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4447 if (lastDrawn[row][column] != board[row][column]) {
\r
4448 SquareToPos(row, column, &x, &y);
\r
4449 clips[num_clips++] =
\r
4450 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4454 for (i=0; i<2; i++) {
\r
4455 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4456 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4457 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4458 lastDrawnHighlight.sq[i].y >= 0) {
\r
4459 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4460 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4461 clips[num_clips++] =
\r
4462 CreateRectRgn(x - lineGap, y - lineGap,
\r
4463 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4465 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4466 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4467 clips[num_clips++] =
\r
4468 CreateRectRgn(x - lineGap, y - lineGap,
\r
4469 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4473 for (i=0; i<2; i++) {
\r
4474 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4475 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4476 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4477 lastDrawnPremove.sq[i].y >= 0) {
\r
4478 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4479 lastDrawnPremove.sq[i].x, &x, &y);
\r
4480 clips[num_clips++] =
\r
4481 CreateRectRgn(x - lineGap, y - lineGap,
\r
4482 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4484 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4485 premoveHighlightInfo.sq[i].y >= 0) {
\r
4486 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4487 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4488 clips[num_clips++] =
\r
4489 CreateRectRgn(x - lineGap, y - lineGap,
\r
4490 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4495 fullrepaint = TRUE;
\r
4498 /* Create a buffer bitmap - this is the actual bitmap
\r
4499 * being written to. When all the work is done, we can
\r
4500 * copy it to the real DC (the screen). This avoids
\r
4501 * the problems with flickering.
\r
4503 GetClientRect(hwndMain, &Rect);
\r
4504 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4505 Rect.bottom-Rect.top+1);
\r
4506 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4507 if (!appData.monoMode) {
\r
4508 SelectPalette(hdcmem, hPal, FALSE);
\r
4511 /* Create clips for dragging */
\r
4512 if (!fullrepaint) {
\r
4513 if (dragInfo.from.x >= 0) {
\r
4514 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4515 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4517 if (dragInfo.start.x >= 0) {
\r
4518 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4519 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4521 if (dragInfo.pos.x >= 0) {
\r
4522 x = dragInfo.pos.x - squareSize / 2;
\r
4523 y = dragInfo.pos.y - squareSize / 2;
\r
4524 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4526 if (dragInfo.lastpos.x >= 0) {
\r
4527 x = dragInfo.lastpos.x - squareSize / 2;
\r
4528 y = dragInfo.lastpos.y - squareSize / 2;
\r
4529 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4533 /* Are we animating a move?
\r
4535 * - remove the piece from the board (temporarely)
\r
4536 * - calculate the clipping region
\r
4538 if (!fullrepaint) {
\r
4539 if (animInfo.piece != EmptySquare) {
\r
4540 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4541 x = boardRect.left + animInfo.lastpos.x;
\r
4542 y = boardRect.top + animInfo.lastpos.y;
\r
4543 x2 = boardRect.left + animInfo.pos.x;
\r
4544 y2 = boardRect.top + animInfo.pos.y;
\r
4545 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4546 /* Slight kludge. The real problem is that after AnimateMove is
\r
4547 done, the position on the screen does not match lastDrawn.
\r
4548 This currently causes trouble only on e.p. captures in
\r
4549 atomic, where the piece moves to an empty square and then
\r
4550 explodes. The old and new positions both had an empty square
\r
4551 at the destination, but animation has drawn a piece there and
\r
4552 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4553 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4557 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4558 if (num_clips == 0)
\r
4559 fullrepaint = TRUE;
\r
4561 /* Set clipping on the memory DC */
\r
4562 if (!fullrepaint) {
\r
4563 SelectClipRgn(hdcmem, clips[0]);
\r
4564 for (x = 1; x < num_clips; x++) {
\r
4565 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4566 abort(); // this should never ever happen!
\r
4570 /* Do all the drawing to the memory DC */
\r
4571 if(explodeInfo.radius) { // [HGM] atomic
\r
4573 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4574 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4575 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4576 x += squareSize/2;
\r
4577 y += squareSize/2;
\r
4578 if(!fullrepaint) {
\r
4579 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4580 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4582 DrawGridOnDC(hdcmem);
\r
4583 DrawHighlightsOnDC(hdcmem);
\r
4584 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4585 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4586 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4587 SelectObject(hdcmem, oldBrush);
\r
4589 DrawGridOnDC(hdcmem);
\r
4590 DrawHighlightsOnDC(hdcmem);
\r
4591 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4594 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4595 if(appData.autoLogo) {
\r
4597 switch(gameMode) { // pick logos based on game mode
\r
4598 case IcsObserving:
\r
4599 whiteLogo = second.programLogo; // ICS logo
\r
4600 blackLogo = second.programLogo;
\r
4603 case IcsPlayingWhite:
\r
4604 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4605 blackLogo = second.programLogo; // ICS logo
\r
4607 case IcsPlayingBlack:
\r
4608 whiteLogo = second.programLogo; // ICS logo
\r
4609 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4611 case TwoMachinesPlay:
\r
4612 if(first.twoMachinesColor[0] == 'b') {
\r
4613 whiteLogo = second.programLogo;
\r
4614 blackLogo = first.programLogo;
\r
4617 case MachinePlaysWhite:
\r
4618 blackLogo = userLogo;
\r
4620 case MachinePlaysBlack:
\r
4621 whiteLogo = userLogo;
\r
4622 blackLogo = first.programLogo;
\r
4625 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4626 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4629 if( appData.highlightMoveWithArrow ) {
\r
4630 DrawArrowHighlight(hdcmem);
\r
4633 DrawCoordsOnDC(hdcmem);
\r
4635 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4636 /* to make sure lastDrawn contains what is actually drawn */
\r
4638 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4639 if (dragged_piece != EmptySquare) {
\r
4640 /* [HGM] or restack */
\r
4641 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4642 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4644 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4645 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4646 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4647 x = dragInfo.pos.x - squareSize / 2;
\r
4648 y = dragInfo.pos.y - squareSize / 2;
\r
4649 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4650 ((int) dragged_piece < (int) BlackPawn),
\r
4651 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4654 /* Put the animated piece back into place and draw it */
\r
4655 if (animInfo.piece != EmptySquare) {
\r
4656 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4657 x = boardRect.left + animInfo.pos.x;
\r
4658 y = boardRect.top + animInfo.pos.y;
\r
4659 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4660 ((int) animInfo.piece < (int) BlackPawn),
\r
4661 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4664 /* Release the bufferBitmap by selecting in the old bitmap
\r
4665 * and delete the memory DC
\r
4667 SelectObject(hdcmem, oldBitmap);
\r
4670 /* Set clipping on the target DC */
\r
4671 if (!fullrepaint) {
\r
4672 SelectClipRgn(hdc, clips[0]);
\r
4673 for (x = 1; x < num_clips; x++) {
\r
4674 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4675 abort(); // this should never ever happen!
\r
4679 /* Copy the new bitmap onto the screen in one go.
\r
4680 * This way we avoid any flickering
\r
4682 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4683 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4684 boardRect.right - boardRect.left,
\r
4685 boardRect.bottom - boardRect.top,
\r
4686 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4687 if(saveDiagFlag) {
\r
4688 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4689 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4691 GetObject(bufferBitmap, sizeof(b), &b);
\r
4692 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4693 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4694 bih.biWidth = b.bmWidth;
\r
4695 bih.biHeight = b.bmHeight;
\r
4697 bih.biBitCount = b.bmBitsPixel;
\r
4698 bih.biCompression = 0;
\r
4699 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4700 bih.biXPelsPerMeter = 0;
\r
4701 bih.biYPelsPerMeter = 0;
\r
4702 bih.biClrUsed = 0;
\r
4703 bih.biClrImportant = 0;
\r
4704 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4705 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4706 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4707 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4709 wb = b.bmWidthBytes;
\r
4711 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4712 int k = ((int*) pData)[i];
\r
4713 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4714 if(j >= 16) break;
\r
4716 if(j >= nrColors) nrColors = j+1;
\r
4718 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4720 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4721 for(w=0; w<(wb>>2); w+=2) {
\r
4722 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4723 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4724 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4725 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4726 pData[p++] = m | j<<4;
\r
4728 while(p&3) pData[p++] = 0;
\r
4731 wb = ((wb+31)>>5)<<2;
\r
4733 // write BITMAPFILEHEADER
\r
4734 fprintf(diagFile, "BM");
\r
4735 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4736 fputDW(diagFile, 0);
\r
4737 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4738 // write BITMAPINFOHEADER
\r
4739 fputDW(diagFile, 40);
\r
4740 fputDW(diagFile, b.bmWidth);
\r
4741 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4742 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4743 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 fputDW(diagFile, 0);
\r
4748 fputDW(diagFile, 0);
\r
4749 fputDW(diagFile, 0);
\r
4750 // write color table
\r
4752 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4753 // write bitmap data
\r
4754 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4755 fputc(pData[i], diagFile);
\r
4759 SelectObject(tmphdc, oldBitmap);
\r
4761 /* Massive cleanup */
\r
4762 for (x = 0; x < num_clips; x++)
\r
4763 DeleteObject(clips[x]);
\r
4766 DeleteObject(bufferBitmap);
\r
4769 ReleaseDC(hwndMain, hdc);
\r
4771 if (lastDrawnFlipView != flipView) {
\r
4773 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4775 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4778 /* CopyBoard(lastDrawn, board);*/
\r
4779 lastDrawnHighlight = highlightInfo;
\r
4780 lastDrawnPremove = premoveHighlightInfo;
\r
4781 lastDrawnFlipView = flipView;
\r
4782 lastDrawnValid = 1;
\r
4785 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4790 saveDiagFlag = 1; diagFile = f;
\r
4791 HDCDrawPosition(NULL, TRUE, NULL);
\r
4795 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4802 /*---------------------------------------------------------------------------*\
\r
4803 | CLIENT PAINT PROCEDURE
\r
4804 | This is the main event-handler for the WM_PAINT message.
\r
4806 \*---------------------------------------------------------------------------*/
\r
4808 PaintProc(HWND hwnd)
\r
4814 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4815 if (IsIconic(hwnd)) {
\r
4816 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4818 if (!appData.monoMode) {
\r
4819 SelectPalette(hdc, hPal, FALSE);
\r
4820 RealizePalette(hdc);
\r
4822 HDCDrawPosition(hdc, 1, NULL);
\r
4824 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4825 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4826 ETO_CLIPPED|ETO_OPAQUE,
\r
4827 &messageRect, messageText, strlen(messageText), NULL);
\r
4828 SelectObject(hdc, oldFont);
\r
4829 DisplayBothClocks();
\r
4831 EndPaint(hwnd,&ps);
\r
4839 * If the user selects on a border boundary, return -1; if off the board,
\r
4840 * return -2. Otherwise map the event coordinate to the square.
\r
4841 * The offset boardRect.left or boardRect.top must already have been
\r
4842 * subtracted from x.
\r
4844 int EventToSquare(x, limit)
\r
4852 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4854 x /= (squareSize + lineGap);
\r
4866 DropEnable dropEnables[] = {
\r
4867 { 'P', DP_Pawn, "Pawn" },
\r
4868 { 'N', DP_Knight, "Knight" },
\r
4869 { 'B', DP_Bishop, "Bishop" },
\r
4870 { 'R', DP_Rook, "Rook" },
\r
4871 { 'Q', DP_Queen, "Queen" },
\r
4875 SetupDropMenu(HMENU hmenu)
\r
4877 int i, count, enable;
\r
4879 extern char white_holding[], black_holding[];
\r
4880 char item[MSG_SIZ];
\r
4882 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4883 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4884 dropEnables[i].piece);
\r
4886 while (p && *p++ == dropEnables[i].piece) count++;
\r
4887 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4888 enable = count > 0 || !appData.testLegality
\r
4889 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4890 && !appData.icsActive);
\r
4891 ModifyMenu(hmenu, dropEnables[i].command,
\r
4892 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4893 dropEnables[i].command, item);
\r
4897 void DragPieceBegin(int x, int y)
\r
4899 dragInfo.lastpos.x = boardRect.left + x;
\r
4900 dragInfo.lastpos.y = boardRect.top + y;
\r
4901 dragInfo.from.x = fromX;
\r
4902 dragInfo.from.y = fromY;
\r
4903 dragInfo.start = dragInfo.from;
\r
4904 SetCapture(hwndMain);
\r
4907 void DragPieceEnd(int x, int y)
\r
4910 dragInfo.start.x = dragInfo.start.y = -1;
\r
4911 dragInfo.from = dragInfo.start;
\r
4912 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4915 /* Event handler for mouse messages */
\r
4917 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4921 static int recursive = 0;
\r
4923 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4926 if (message == WM_MBUTTONUP) {
\r
4927 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4928 to the middle button: we simulate pressing the left button too!
\r
4930 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4931 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4937 pt.x = LOWORD(lParam);
\r
4938 pt.y = HIWORD(lParam);
\r
4939 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4940 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4941 if (!flipView && y >= 0) {
\r
4942 y = BOARD_HEIGHT - 1 - y;
\r
4944 if (flipView && x >= 0) {
\r
4945 x = BOARD_WIDTH - 1 - x;
\r
4948 switch (message) {
\r
4949 case WM_LBUTTONDOWN:
\r
4950 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4951 if (gameMode == EditPosition) {
\r
4952 SetWhiteToPlayEvent();
\r
4953 } else if (gameMode == IcsPlayingBlack ||
\r
4954 gameMode == MachinePlaysWhite) {
\r
4956 } else if (gameMode == EditGame) {
\r
4957 AdjustClock(flipClock, -1);
\r
4959 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4960 if (gameMode == EditPosition) {
\r
4961 SetBlackToPlayEvent();
\r
4962 } else if (gameMode == IcsPlayingWhite ||
\r
4963 gameMode == MachinePlaysBlack) {
\r
4965 } else if (gameMode == EditGame) {
\r
4966 AdjustClock(!flipClock, -1);
\r
4969 dragInfo.start.x = dragInfo.start.y = -1;
\r
4970 dragInfo.from = dragInfo.start;
\r
4971 if(fromX == -1 && frozen) { // not sure where this is for
\r
4972 fromX = fromY = -1;
\r
4973 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4976 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4977 DrawPosition(TRUE, NULL);
\r
4980 case WM_LBUTTONUP:
\r
4981 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4982 DrawPosition(TRUE, NULL);
\r
4985 case WM_MOUSEMOVE:
\r
4986 if ((appData.animateDragging || appData.highlightDragging)
\r
4987 && (wParam & MK_LBUTTON)
\r
4988 && dragInfo.from.x >= 0)
\r
4990 BOOL full_repaint = FALSE;
\r
4992 if (appData.animateDragging) {
\r
4993 dragInfo.pos = pt;
\r
4995 if (appData.highlightDragging) {
\r
4996 SetHighlights(fromX, fromY, x, y);
\r
4997 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4998 full_repaint = TRUE;
\r
5002 DrawPosition( full_repaint, NULL);
\r
5004 dragInfo.lastpos = dragInfo.pos;
\r
5008 case WM_MOUSEWHEEL: // [DM]
\r
5009 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5010 /* Mouse Wheel is being rolled forward
\r
5011 * Play moves forward
\r
5013 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5014 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5015 /* Mouse Wheel is being rolled backward
\r
5016 * Play moves backward
\r
5018 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5019 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5023 case WM_MBUTTONDOWN:
\r
5024 case WM_RBUTTONDOWN:
\r
5027 fromX = fromY = -1;
\r
5028 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5029 dragInfo.start.x = dragInfo.start.y = -1;
\r
5030 dragInfo.from = dragInfo.start;
\r
5031 dragInfo.lastpos = dragInfo.pos;
\r
5032 if (appData.highlightDragging) {
\r
5033 ClearHighlights();
\r
5036 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5037 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5038 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5039 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5040 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5043 DrawPosition(TRUE, NULL);
\r
5045 switch (gameMode) {
\r
5046 case EditPosition:
\r
5047 case IcsExamining:
\r
5048 if (x < 0 || y < 0) break;
\r
5051 if (message == WM_MBUTTONDOWN) {
\r
5052 buttonCount = 3; /* even if system didn't think so */
\r
5053 if (wParam & MK_SHIFT)
\r
5054 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5056 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5057 } else { /* message == WM_RBUTTONDOWN */
\r
5058 /* Just have one menu, on the right button. Windows users don't
\r
5059 think to try the middle one, and sometimes other software steals
\r
5060 it, or it doesn't really exist. */
\r
5061 if(gameInfo.variant != VariantShogi)
\r
5062 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5064 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5067 case IcsPlayingWhite:
\r
5068 case IcsPlayingBlack:
\r
5070 case MachinePlaysWhite:
\r
5071 case MachinePlaysBlack:
\r
5072 if (appData.testLegality &&
\r
5073 gameInfo.variant != VariantBughouse &&
\r
5074 gameInfo.variant != VariantCrazyhouse) break;
\r
5075 if (x < 0 || y < 0) break;
\r
5078 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5079 SetupDropMenu(hmenu);
\r
5080 MenuPopup(hwnd, pt, hmenu, -1);
\r
5091 /* Preprocess messages for buttons in main window */
\r
5093 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5095 int id = GetWindowLong(hwnd, GWL_ID);
\r
5098 for (i=0; i<N_BUTTONS; i++) {
\r
5099 if (buttonDesc[i].id == id) break;
\r
5101 if (i == N_BUTTONS) return 0;
\r
5102 switch (message) {
\r
5107 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5108 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5115 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5118 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5119 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5120 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5121 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5123 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5125 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5126 PopUpMoveDialog((char)wParam);
\r
5132 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5135 /* Process messages for Promotion dialog box */
\r
5137 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5141 switch (message) {
\r
5142 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5143 /* Center the dialog over the application window */
\r
5144 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5145 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5146 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5147 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5148 SW_SHOW : SW_HIDE);
\r
5149 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5150 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5151 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5152 PieceToChar(WhiteAngel) != '~') ||
\r
5153 (PieceToChar(BlackAngel) >= 'A' &&
\r
5154 PieceToChar(BlackAngel) != '~') ) ?
\r
5155 SW_SHOW : SW_HIDE);
\r
5156 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5157 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5158 PieceToChar(WhiteMarshall) != '~') ||
\r
5159 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5160 PieceToChar(BlackMarshall) != '~') ) ?
\r
5161 SW_SHOW : SW_HIDE);
\r
5162 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5163 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5164 gameInfo.variant != VariantShogi ?
\r
5165 SW_SHOW : SW_HIDE);
\r
5166 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5167 gameInfo.variant != VariantShogi ?
\r
5168 SW_SHOW : SW_HIDE);
\r
5169 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5170 gameInfo.variant == VariantShogi ?
\r
5171 SW_SHOW : SW_HIDE);
\r
5172 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5173 gameInfo.variant == VariantShogi ?
\r
5174 SW_SHOW : SW_HIDE);
\r
5175 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5176 gameInfo.variant == VariantSuper ?
\r
5177 SW_SHOW : SW_HIDE);
\r
5180 case WM_COMMAND: /* message: received a command */
\r
5181 switch (LOWORD(wParam)) {
\r
5183 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5184 ClearHighlights();
\r
5185 DrawPosition(FALSE, NULL);
\r
5188 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5191 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5194 promoChar = PieceToChar(BlackRook);
\r
5197 promoChar = PieceToChar(BlackBishop);
\r
5199 case PB_Chancellor:
\r
5200 promoChar = PieceToChar(BlackMarshall);
\r
5202 case PB_Archbishop:
\r
5203 promoChar = PieceToChar(BlackAngel);
\r
5206 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5211 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5212 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5213 only show the popup when we are already sure the move is valid or
\r
5214 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5215 will figure out it is a promotion from the promoChar. */
\r
5216 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5217 fromX = fromY = -1;
\r
5218 if (!appData.highlightLastMove) {
\r
5219 ClearHighlights();
\r
5220 DrawPosition(FALSE, NULL);
\r
5227 /* Pop up promotion dialog */
\r
5229 PromotionPopup(HWND hwnd)
\r
5233 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5234 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5235 hwnd, (DLGPROC)lpProc);
\r
5236 FreeProcInstance(lpProc);
\r
5242 DrawPosition(TRUE, NULL);
\r
5243 PromotionPopup(hwndMain);
\r
5246 /* Toggle ShowThinking */
\r
5248 ToggleShowThinking()
\r
5250 appData.showThinking = !appData.showThinking;
\r
5251 ShowThinkingEvent();
\r
5255 LoadGameDialog(HWND hwnd, char* title)
\r
5259 char fileTitle[MSG_SIZ];
\r
5260 f = OpenFileDialog(hwnd, "rb", "",
\r
5261 appData.oldSaveStyle ? "gam" : "pgn",
\r
5263 title, &number, fileTitle, NULL);
\r
5265 cmailMsgLoaded = FALSE;
\r
5266 if (number == 0) {
\r
5267 int error = GameListBuild(f);
\r
5269 DisplayError("Cannot build game list", error);
\r
5270 } else if (!ListEmpty(&gameList) &&
\r
5271 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5272 GameListPopUp(f, fileTitle);
\r
5275 GameListDestroy();
\r
5278 LoadGame(f, number, fileTitle, FALSE);
\r
5282 int get_term_width()
\r
5287 HFONT hfont, hold_font;
\r
5292 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5296 // get the text metrics
\r
5297 hdc = GetDC(hText);
\r
5298 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5299 if (consoleCF.dwEffects & CFE_BOLD)
\r
5300 lf.lfWeight = FW_BOLD;
\r
5301 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5302 lf.lfItalic = TRUE;
\r
5303 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5304 lf.lfStrikeOut = TRUE;
\r
5305 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5306 lf.lfUnderline = TRUE;
\r
5307 hfont = CreateFontIndirect(&lf);
\r
5308 hold_font = SelectObject(hdc, hfont);
\r
5309 GetTextMetrics(hdc, &tm);
\r
5310 SelectObject(hdc, hold_font);
\r
5311 DeleteObject(hfont);
\r
5312 ReleaseDC(hText, hdc);
\r
5314 // get the rectangle
\r
5315 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5317 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5320 void UpdateICSWidth(HWND hText)
\r
5322 LONG old_width, new_width;
\r
5324 new_width = get_term_width(hText, FALSE);
\r
5325 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5326 if (new_width != old_width)
\r
5328 ics_update_width(new_width);
\r
5329 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5334 ChangedConsoleFont()
\r
5337 CHARRANGE tmpsel, sel;
\r
5338 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5339 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5340 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5343 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5344 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5345 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5346 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5347 * size. This was undocumented in the version of MSVC++ that I had
\r
5348 * when I wrote the code, but is apparently documented now.
\r
5350 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5351 cfmt.bCharSet = f->lf.lfCharSet;
\r
5352 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5353 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5354 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5355 /* Why are the following seemingly needed too? */
\r
5356 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5357 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5358 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5360 tmpsel.cpMax = -1; /*999999?*/
\r
5361 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5362 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5363 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5364 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5366 paraf.cbSize = sizeof(paraf);
\r
5367 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5368 paraf.dxStartIndent = 0;
\r
5369 paraf.dxOffset = WRAP_INDENT;
\r
5370 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5371 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5372 UpdateICSWidth(hText);
\r
5375 /*---------------------------------------------------------------------------*\
\r
5377 * Window Proc for main window
\r
5379 \*---------------------------------------------------------------------------*/
\r
5381 /* Process messages for main window, etc. */
\r
5383 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5386 int wmId, wmEvent;
\r
5390 char fileTitle[MSG_SIZ];
\r
5391 char buf[MSG_SIZ];
\r
5392 static SnapData sd;
\r
5394 switch (message) {
\r
5396 case WM_PAINT: /* message: repaint portion of window */
\r
5400 case WM_ERASEBKGND:
\r
5401 if (IsIconic(hwnd)) {
\r
5402 /* Cheat; change the message */
\r
5403 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5405 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5409 case WM_LBUTTONDOWN:
\r
5410 case WM_MBUTTONDOWN:
\r
5411 case WM_RBUTTONDOWN:
\r
5412 case WM_LBUTTONUP:
\r
5413 case WM_MBUTTONUP:
\r
5414 case WM_RBUTTONUP:
\r
5415 case WM_MOUSEMOVE:
\r
5416 case WM_MOUSEWHEEL:
\r
5417 MouseEvent(hwnd, message, wParam, lParam);
\r
5420 JAWS_KB_NAVIGATION
\r
5424 JAWS_ALT_INTERCEPT
\r
5426 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5427 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5428 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5429 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5431 SendMessage(h, message, wParam, lParam);
\r
5432 } else if(lParam != KF_REPEAT) {
\r
5433 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5434 PopUpMoveDialog((char)wParam);
\r
5435 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5436 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5441 case WM_PALETTECHANGED:
\r
5442 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5444 HDC hdc = GetDC(hwndMain);
\r
5445 SelectPalette(hdc, hPal, TRUE);
\r
5446 nnew = RealizePalette(hdc);
\r
5448 paletteChanged = TRUE;
\r
5449 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5451 ReleaseDC(hwnd, hdc);
\r
5455 case WM_QUERYNEWPALETTE:
\r
5456 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5458 HDC hdc = GetDC(hwndMain);
\r
5459 paletteChanged = FALSE;
\r
5460 SelectPalette(hdc, hPal, FALSE);
\r
5461 nnew = RealizePalette(hdc);
\r
5463 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5465 ReleaseDC(hwnd, hdc);
\r
5470 case WM_COMMAND: /* message: command from application menu */
\r
5471 wmId = LOWORD(wParam);
\r
5472 wmEvent = HIWORD(wParam);
\r
5477 SAY("new game enter a move to play against the computer with white");
\r
5480 case IDM_NewGameFRC:
\r
5481 if( NewGameFRC() == 0 ) {
\r
5486 case IDM_NewVariant:
\r
5487 NewVariantPopup(hwnd);
\r
5490 case IDM_LoadGame:
\r
5491 LoadGameDialog(hwnd, "Load Game from File");
\r
5494 case IDM_LoadNextGame:
\r
5498 case IDM_LoadPrevGame:
\r
5502 case IDM_ReloadGame:
\r
5506 case IDM_LoadPosition:
\r
5507 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5508 Reset(FALSE, TRUE);
\r
5511 f = OpenFileDialog(hwnd, "rb", "",
\r
5512 appData.oldSaveStyle ? "pos" : "fen",
\r
5514 "Load Position from File", &number, fileTitle, NULL);
\r
5516 LoadPosition(f, number, fileTitle);
\r
5520 case IDM_LoadNextPosition:
\r
5521 ReloadPosition(1);
\r
5524 case IDM_LoadPrevPosition:
\r
5525 ReloadPosition(-1);
\r
5528 case IDM_ReloadPosition:
\r
5529 ReloadPosition(0);
\r
5532 case IDM_SaveGame:
\r
5533 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5534 f = OpenFileDialog(hwnd, "a", defName,
\r
5535 appData.oldSaveStyle ? "gam" : "pgn",
\r
5537 "Save Game to File", NULL, fileTitle, NULL);
\r
5539 SaveGame(f, 0, "");
\r
5543 case IDM_SavePosition:
\r
5544 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5545 f = OpenFileDialog(hwnd, "a", defName,
\r
5546 appData.oldSaveStyle ? "pos" : "fen",
\r
5548 "Save Position to File", NULL, fileTitle, NULL);
\r
5550 SavePosition(f, 0, "");
\r
5554 case IDM_SaveDiagram:
\r
5555 defName = "diagram";
\r
5556 f = OpenFileDialog(hwnd, "wb", defName,
\r
5559 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5565 case IDM_CopyGame:
\r
5566 CopyGameToClipboard();
\r
5569 case IDM_PasteGame:
\r
5570 PasteGameFromClipboard();
\r
5573 case IDM_CopyGameListToClipboard:
\r
5574 CopyGameListToClipboard();
\r
5577 /* [AS] Autodetect FEN or PGN data */
\r
5578 case IDM_PasteAny:
\r
5579 PasteGameOrFENFromClipboard();
\r
5582 /* [AS] Move history */
\r
5583 case IDM_ShowMoveHistory:
\r
5584 if( MoveHistoryIsUp() ) {
\r
5585 MoveHistoryPopDown();
\r
5588 MoveHistoryPopUp();
\r
5592 /* [AS] Eval graph */
\r
5593 case IDM_ShowEvalGraph:
\r
5594 if( EvalGraphIsUp() ) {
\r
5595 EvalGraphPopDown();
\r
5599 SetFocus(hwndMain);
\r
5603 /* [AS] Engine output */
\r
5604 case IDM_ShowEngineOutput:
\r
5605 if( EngineOutputIsUp() ) {
\r
5606 EngineOutputPopDown();
\r
5609 EngineOutputPopUp();
\r
5613 /* [AS] User adjudication */
\r
5614 case IDM_UserAdjudication_White:
\r
5615 UserAdjudicationEvent( +1 );
\r
5618 case IDM_UserAdjudication_Black:
\r
5619 UserAdjudicationEvent( -1 );
\r
5622 case IDM_UserAdjudication_Draw:
\r
5623 UserAdjudicationEvent( 0 );
\r
5626 /* [AS] Game list options dialog */
\r
5627 case IDM_GameListOptions:
\r
5628 GameListOptions();
\r
5635 case IDM_CopyPosition:
\r
5636 CopyFENToClipboard();
\r
5639 case IDM_PastePosition:
\r
5640 PasteFENFromClipboard();
\r
5643 case IDM_MailMove:
\r
5647 case IDM_ReloadCMailMsg:
\r
5648 Reset(TRUE, TRUE);
\r
5649 ReloadCmailMsgEvent(FALSE);
\r
5652 case IDM_Minimize:
\r
5653 ShowWindow(hwnd, SW_MINIMIZE);
\r
5660 case IDM_MachineWhite:
\r
5661 MachineWhiteEvent();
\r
5663 * refresh the tags dialog only if it's visible
\r
5665 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5667 tags = PGNTags(&gameInfo);
\r
5668 TagsPopUp(tags, CmailMsg());
\r
5671 SAY("computer starts playing white");
\r
5674 case IDM_MachineBlack:
\r
5675 MachineBlackEvent();
\r
5677 * refresh the tags dialog only if it's visible
\r
5679 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5681 tags = PGNTags(&gameInfo);
\r
5682 TagsPopUp(tags, CmailMsg());
\r
5685 SAY("computer starts playing black");
\r
5688 case IDM_TwoMachines:
\r
5689 TwoMachinesEvent();
\r
5691 * refresh the tags dialog only if it's visible
\r
5693 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5695 tags = PGNTags(&gameInfo);
\r
5696 TagsPopUp(tags, CmailMsg());
\r
5699 SAY("programs start playing each other");
\r
5702 case IDM_AnalysisMode:
\r
5703 if (!first.analysisSupport) {
\r
5704 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5705 DisplayError(buf, 0);
\r
5707 SAY("analyzing current position");
\r
5708 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5709 if (appData.icsActive) {
\r
5710 if (gameMode != IcsObserving) {
\r
5711 sprintf(buf, "You are not observing a game");
\r
5712 DisplayError(buf, 0);
\r
5713 /* secure check */
\r
5714 if (appData.icsEngineAnalyze) {
\r
5715 if (appData.debugMode)
\r
5716 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5717 ExitAnalyzeMode();
\r
5723 /* if enable, user want disable icsEngineAnalyze */
\r
5724 if (appData.icsEngineAnalyze) {
\r
5725 ExitAnalyzeMode();
\r
5729 appData.icsEngineAnalyze = TRUE;
\r
5730 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5733 if (!appData.showThinking) ToggleShowThinking();
\r
5734 AnalyzeModeEvent();
\r
5738 case IDM_AnalyzeFile:
\r
5739 if (!first.analysisSupport) {
\r
5740 char buf[MSG_SIZ];
\r
5741 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5742 DisplayError(buf, 0);
\r
5744 if (!appData.showThinking) ToggleShowThinking();
\r
5745 AnalyzeFileEvent();
\r
5746 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5747 AnalysisPeriodicEvent(1);
\r
5751 case IDM_IcsClient:
\r
5755 case IDM_EditGame:
\r
5760 case IDM_EditPosition:
\r
5761 EditPositionEvent();
\r
5762 SAY("to set up a position type a FEN");
\r
5765 case IDM_Training:
\r
5769 case IDM_ShowGameList:
\r
5770 ShowGameListProc();
\r
5773 case IDM_EditTags:
\r
5777 case IDM_EditComment:
\r
5778 if (commentDialogUp && editComment) {
\r
5781 EditCommentEvent();
\r
5801 case IDM_CallFlag:
\r
5821 case IDM_StopObserving:
\r
5822 StopObservingEvent();
\r
5825 case IDM_StopExamining:
\r
5826 StopExaminingEvent();
\r
5829 case IDM_TypeInMove:
\r
5830 PopUpMoveDialog('\000');
\r
5833 case IDM_TypeInName:
\r
5834 PopUpNameDialog('\000');
\r
5837 case IDM_Backward:
\r
5839 SetFocus(hwndMain);
\r
5846 SetFocus(hwndMain);
\r
5851 SetFocus(hwndMain);
\r
5856 SetFocus(hwndMain);
\r
5863 case IDM_TruncateGame:
\r
5864 TruncateGameEvent();
\r
5871 case IDM_RetractMove:
\r
5872 RetractMoveEvent();
\r
5875 case IDM_FlipView:
\r
5876 flipView = !flipView;
\r
5877 DrawPosition(FALSE, NULL);
\r
5880 case IDM_FlipClock:
\r
5881 flipClock = !flipClock;
\r
5882 DisplayBothClocks();
\r
5883 DrawPosition(FALSE, NULL);
\r
5886 case IDM_MuteSounds:
\r
5887 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5888 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5889 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5892 case IDM_GeneralOptions:
\r
5893 GeneralOptionsPopup(hwnd);
\r
5894 DrawPosition(TRUE, NULL);
\r
5897 case IDM_BoardOptions:
\r
5898 BoardOptionsPopup(hwnd);
\r
5901 case IDM_EnginePlayOptions:
\r
5902 EnginePlayOptionsPopup(hwnd);
\r
5905 case IDM_Engine1Options:
\r
5906 EngineOptionsPopup(hwnd, &first);
\r
5909 case IDM_Engine2Options:
\r
5910 EngineOptionsPopup(hwnd, &second);
\r
5913 case IDM_OptionsUCI:
\r
5914 UciOptionsPopup(hwnd);
\r
5917 case IDM_IcsOptions:
\r
5918 IcsOptionsPopup(hwnd);
\r
5922 FontsOptionsPopup(hwnd);
\r
5926 SoundOptionsPopup(hwnd);
\r
5929 case IDM_CommPort:
\r
5930 CommPortOptionsPopup(hwnd);
\r
5933 case IDM_LoadOptions:
\r
5934 LoadOptionsPopup(hwnd);
\r
5937 case IDM_SaveOptions:
\r
5938 SaveOptionsPopup(hwnd);
\r
5941 case IDM_TimeControl:
\r
5942 TimeControlOptionsPopup(hwnd);
\r
5945 case IDM_SaveSettings:
\r
5946 SaveSettings(settingsFileName);
\r
5949 case IDM_SaveSettingsOnExit:
\r
5950 saveSettingsOnExit = !saveSettingsOnExit;
\r
5951 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5952 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5953 MF_CHECKED : MF_UNCHECKED));
\r
5964 case IDM_AboutGame:
\r
5969 appData.debugMode = !appData.debugMode;
\r
5970 if (appData.debugMode) {
\r
5971 char dir[MSG_SIZ];
\r
5972 GetCurrentDirectory(MSG_SIZ, dir);
\r
5973 SetCurrentDirectory(installDir);
\r
5974 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5975 SetCurrentDirectory(dir);
\r
5976 setbuf(debugFP, NULL);
\r
5983 case IDM_HELPCONTENTS:
\r
5984 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5985 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5986 MessageBox (GetFocus(),
\r
5987 "Unable to activate help",
\r
5988 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5992 case IDM_HELPSEARCH:
\r
5993 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5994 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5995 MessageBox (GetFocus(),
\r
5996 "Unable to activate help",
\r
5997 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6001 case IDM_HELPHELP:
\r
6002 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6003 MessageBox (GetFocus(),
\r
6004 "Unable to activate help",
\r
6005 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6010 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6012 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6013 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6014 FreeProcInstance(lpProc);
\r
6017 case IDM_DirectCommand1:
\r
6018 AskQuestionEvent("Direct Command",
\r
6019 "Send to chess program:", "", "1");
\r
6021 case IDM_DirectCommand2:
\r
6022 AskQuestionEvent("Direct Command",
\r
6023 "Send to second chess program:", "", "2");
\r
6026 case EP_WhitePawn:
\r
6027 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6028 fromX = fromY = -1;
\r
6031 case EP_WhiteKnight:
\r
6032 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6033 fromX = fromY = -1;
\r
6036 case EP_WhiteBishop:
\r
6037 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6038 fromX = fromY = -1;
\r
6041 case EP_WhiteRook:
\r
6042 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6043 fromX = fromY = -1;
\r
6046 case EP_WhiteQueen:
\r
6047 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6048 fromX = fromY = -1;
\r
6051 case EP_WhiteFerz:
\r
6052 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6053 fromX = fromY = -1;
\r
6056 case EP_WhiteWazir:
\r
6057 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6058 fromX = fromY = -1;
\r
6061 case EP_WhiteAlfil:
\r
6062 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6063 fromX = fromY = -1;
\r
6066 case EP_WhiteCannon:
\r
6067 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6068 fromX = fromY = -1;
\r
6071 case EP_WhiteCardinal:
\r
6072 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6073 fromX = fromY = -1;
\r
6076 case EP_WhiteMarshall:
\r
6077 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6078 fromX = fromY = -1;
\r
6081 case EP_WhiteKing:
\r
6082 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6083 fromX = fromY = -1;
\r
6086 case EP_BlackPawn:
\r
6087 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6088 fromX = fromY = -1;
\r
6091 case EP_BlackKnight:
\r
6092 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6093 fromX = fromY = -1;
\r
6096 case EP_BlackBishop:
\r
6097 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6098 fromX = fromY = -1;
\r
6101 case EP_BlackRook:
\r
6102 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6103 fromX = fromY = -1;
\r
6106 case EP_BlackQueen:
\r
6107 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6108 fromX = fromY = -1;
\r
6111 case EP_BlackFerz:
\r
6112 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6113 fromX = fromY = -1;
\r
6116 case EP_BlackWazir:
\r
6117 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6118 fromX = fromY = -1;
\r
6121 case EP_BlackAlfil:
\r
6122 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6123 fromX = fromY = -1;
\r
6126 case EP_BlackCannon:
\r
6127 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6128 fromX = fromY = -1;
\r
6131 case EP_BlackCardinal:
\r
6132 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6133 fromX = fromY = -1;
\r
6136 case EP_BlackMarshall:
\r
6137 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6138 fromX = fromY = -1;
\r
6141 case EP_BlackKing:
\r
6142 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6143 fromX = fromY = -1;
\r
6146 case EP_EmptySquare:
\r
6147 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6148 fromX = fromY = -1;
\r
6151 case EP_ClearBoard:
\r
6152 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6153 fromX = fromY = -1;
\r
6157 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6158 fromX = fromY = -1;
\r
6162 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6163 fromX = fromY = -1;
\r
6167 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6168 fromX = fromY = -1;
\r
6172 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6173 fromX = fromY = -1;
\r
6177 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6178 fromX = fromY = -1;
\r
6182 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6183 fromX = fromY = -1;
\r
6187 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6188 fromX = fromY = -1;
\r
6192 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6193 fromX = fromY = -1;
\r
6197 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6198 fromX = fromY = -1;
\r
6202 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6208 case CLOCK_TIMER_ID:
\r
6209 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6210 clockTimerEvent = 0;
\r
6211 DecrementClocks(); /* call into back end */
\r
6213 case LOAD_GAME_TIMER_ID:
\r
6214 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6215 loadGameTimerEvent = 0;
\r
6216 AutoPlayGameLoop(); /* call into back end */
\r
6218 case ANALYSIS_TIMER_ID:
\r
6219 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6220 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6221 AnalysisPeriodicEvent(0);
\r
6223 KillTimer(hwnd, analysisTimerEvent);
\r
6224 analysisTimerEvent = 0;
\r
6227 case DELAYED_TIMER_ID:
\r
6228 KillTimer(hwnd, delayedTimerEvent);
\r
6229 delayedTimerEvent = 0;
\r
6230 delayedTimerCallback();
\r
6235 case WM_USER_Input:
\r
6236 InputEvent(hwnd, message, wParam, lParam);
\r
6239 /* [AS] Also move "attached" child windows */
\r
6240 case WM_WINDOWPOSCHANGING:
\r
6242 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6243 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6245 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6246 /* Window is moving */
\r
6249 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6250 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6251 rcMain.right = boardX + winWidth;
\r
6252 rcMain.top = boardY;
\r
6253 rcMain.bottom = boardY + winHeight;
\r
6255 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6256 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6257 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6258 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6259 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6266 /* [AS] Snapping */
\r
6267 case WM_ENTERSIZEMOVE:
\r
6268 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6269 if (hwnd == hwndMain) {
\r
6270 doingSizing = TRUE;
\r
6273 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6277 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6278 if (hwnd == hwndMain) {
\r
6279 lastSizing = wParam;
\r
6284 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6285 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6287 case WM_EXITSIZEMOVE:
\r
6288 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6289 if (hwnd == hwndMain) {
\r
6291 doingSizing = FALSE;
\r
6292 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6293 GetClientRect(hwnd, &client);
\r
6294 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6296 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6298 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6301 case WM_DESTROY: /* message: window being destroyed */
\r
6302 PostQuitMessage(0);
\r
6306 if (hwnd == hwndMain) {
\r
6311 default: /* Passes it on if unprocessed */
\r
6312 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6317 /*---------------------------------------------------------------------------*\
\r
6319 * Misc utility routines
\r
6321 \*---------------------------------------------------------------------------*/
\r
6324 * Decent random number generator, at least not as bad as Windows
\r
6325 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6327 unsigned int randstate;
\r
6332 randstate = randstate * 1664525 + 1013904223;
\r
6333 return (int) randstate & 0x7fffffff;
\r
6337 mysrandom(unsigned int seed)
\r
6344 * returns TRUE if user selects a different color, FALSE otherwise
\r
6348 ChangeColor(HWND hwnd, COLORREF *which)
\r
6350 static BOOL firstTime = TRUE;
\r
6351 static DWORD customColors[16];
\r
6353 COLORREF newcolor;
\r
6358 /* Make initial colors in use available as custom colors */
\r
6359 /* Should we put the compiled-in defaults here instead? */
\r
6361 customColors[i++] = lightSquareColor & 0xffffff;
\r
6362 customColors[i++] = darkSquareColor & 0xffffff;
\r
6363 customColors[i++] = whitePieceColor & 0xffffff;
\r
6364 customColors[i++] = blackPieceColor & 0xffffff;
\r
6365 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6366 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6368 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6369 customColors[i++] = textAttribs[ccl].color;
\r
6371 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6372 firstTime = FALSE;
\r
6375 cc.lStructSize = sizeof(cc);
\r
6376 cc.hwndOwner = hwnd;
\r
6377 cc.hInstance = NULL;
\r
6378 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6379 cc.lpCustColors = (LPDWORD) customColors;
\r
6380 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6382 if (!ChooseColor(&cc)) return FALSE;
\r
6384 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6385 if (newcolor == *which) return FALSE;
\r
6386 *which = newcolor;
\r
6390 InitDrawingColors();
\r
6391 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6396 MyLoadSound(MySound *ms)
\r
6402 if (ms->data) free(ms->data);
\r
6405 switch (ms->name[0]) {
\r
6411 /* System sound from Control Panel. Don't preload here. */
\r
6415 if (ms->name[1] == NULLCHAR) {
\r
6416 /* "!" alone = silence */
\r
6419 /* Builtin wave resource. Error if not found. */
\r
6420 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6421 if (h == NULL) break;
\r
6422 ms->data = (void *)LoadResource(hInst, h);
\r
6423 if (h == NULL) break;
\r
6428 /* .wav file. Error if not found. */
\r
6429 f = fopen(ms->name, "rb");
\r
6430 if (f == NULL) break;
\r
6431 if (fstat(fileno(f), &st) < 0) break;
\r
6432 ms->data = malloc(st.st_size);
\r
6433 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6439 char buf[MSG_SIZ];
\r
6440 sprintf(buf, "Error loading sound %s", ms->name);
\r
6441 DisplayError(buf, GetLastError());
\r
6447 MyPlaySound(MySound *ms)
\r
6449 BOOLEAN ok = FALSE;
\r
6451 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6452 switch (ms->name[0]) {
\r
6454 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6459 /* System sound from Control Panel (deprecated feature).
\r
6460 "$" alone or an unset sound name gets default beep (still in use). */
\r
6461 if (ms->name[1]) {
\r
6462 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6464 if (!ok) ok = MessageBeep(MB_OK);
\r
6467 /* Builtin wave resource, or "!" alone for silence */
\r
6468 if (ms->name[1]) {
\r
6469 if (ms->data == NULL) return FALSE;
\r
6470 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6476 /* .wav file. Error if not found. */
\r
6477 if (ms->data == NULL) return FALSE;
\r
6478 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6481 /* Don't print an error: this can happen innocently if the sound driver
\r
6482 is busy; for instance, if another instance of WinBoard is playing
\r
6483 a sound at about the same time. */
\r
6489 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6492 OPENFILENAME *ofn;
\r
6493 static UINT *number; /* gross that this is static */
\r
6495 switch (message) {
\r
6496 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6497 /* Center the dialog over the application window */
\r
6498 ofn = (OPENFILENAME *) lParam;
\r
6499 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6500 number = (UINT *) ofn->lCustData;
\r
6501 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6505 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6506 return FALSE; /* Allow for further processing */
\r
6509 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6510 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6512 return FALSE; /* Allow for further processing */
\r
6518 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6520 static UINT *number;
\r
6521 OPENFILENAME *ofname;
\r
6524 case WM_INITDIALOG:
\r
6525 ofname = (OPENFILENAME *)lParam;
\r
6526 number = (UINT *)(ofname->lCustData);
\r
6529 ofnot = (OFNOTIFY *)lParam;
\r
6530 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6531 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6540 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6541 char *nameFilt, char *dlgTitle, UINT *number,
\r
6542 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6544 OPENFILENAME openFileName;
\r
6545 char buf1[MSG_SIZ];
\r
6548 if (fileName == NULL) fileName = buf1;
\r
6549 if (defName == NULL) {
\r
6550 strcpy(fileName, "*.");
\r
6551 strcat(fileName, defExt);
\r
6553 strcpy(fileName, defName);
\r
6555 if (fileTitle) strcpy(fileTitle, "");
\r
6556 if (number) *number = 0;
\r
6558 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6559 openFileName.hwndOwner = hwnd;
\r
6560 openFileName.hInstance = (HANDLE) hInst;
\r
6561 openFileName.lpstrFilter = nameFilt;
\r
6562 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6563 openFileName.nMaxCustFilter = 0L;
\r
6564 openFileName.nFilterIndex = 1L;
\r
6565 openFileName.lpstrFile = fileName;
\r
6566 openFileName.nMaxFile = MSG_SIZ;
\r
6567 openFileName.lpstrFileTitle = fileTitle;
\r
6568 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6569 openFileName.lpstrInitialDir = NULL;
\r
6570 openFileName.lpstrTitle = dlgTitle;
\r
6571 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6572 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6573 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6574 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6575 openFileName.nFileOffset = 0;
\r
6576 openFileName.nFileExtension = 0;
\r
6577 openFileName.lpstrDefExt = defExt;
\r
6578 openFileName.lCustData = (LONG) number;
\r
6579 openFileName.lpfnHook = oldDialog ?
\r
6580 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6581 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6583 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6584 GetOpenFileName(&openFileName)) {
\r
6585 /* open the file */
\r
6586 f = fopen(openFileName.lpstrFile, write);
\r
6588 MessageBox(hwnd, "File open failed", NULL,
\r
6589 MB_OK|MB_ICONEXCLAMATION);
\r
6593 int err = CommDlgExtendedError();
\r
6594 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6603 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6605 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6608 * Get the first pop-up menu in the menu template. This is the
\r
6609 * menu that TrackPopupMenu displays.
\r
6611 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6613 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6616 * TrackPopup uses screen coordinates, so convert the
\r
6617 * coordinates of the mouse click to screen coordinates.
\r
6619 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6621 /* Draw and track the floating pop-up menu. */
\r
6622 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6623 pt.x, pt.y, 0, hwnd, NULL);
\r
6625 /* Destroy the menu.*/
\r
6626 DestroyMenu(hmenu);
\r
6631 int sizeX, sizeY, newSizeX, newSizeY;
\r
6633 } ResizeEditPlusButtonsClosure;
\r
6636 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6638 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6642 if (hChild == cl->hText) return TRUE;
\r
6643 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6644 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6645 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6646 ScreenToClient(cl->hDlg, &pt);
\r
6647 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6648 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6652 /* Resize a dialog that has a (rich) edit field filling most of
\r
6653 the top, with a row of buttons below */
\r
6655 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6658 int newTextHeight, newTextWidth;
\r
6659 ResizeEditPlusButtonsClosure cl;
\r
6661 /*if (IsIconic(hDlg)) return;*/
\r
6662 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6664 cl.hdwp = BeginDeferWindowPos(8);
\r
6666 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6667 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6668 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6669 if (newTextHeight < 0) {
\r
6670 newSizeY += -newTextHeight;
\r
6671 newTextHeight = 0;
\r
6673 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6674 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6680 cl.newSizeX = newSizeX;
\r
6681 cl.newSizeY = newSizeY;
\r
6682 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6684 EndDeferWindowPos(cl.hdwp);
\r
6687 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6689 RECT rChild, rParent;
\r
6690 int wChild, hChild, wParent, hParent;
\r
6691 int wScreen, hScreen, xNew, yNew;
\r
6694 /* Get the Height and Width of the child window */
\r
6695 GetWindowRect (hwndChild, &rChild);
\r
6696 wChild = rChild.right - rChild.left;
\r
6697 hChild = rChild.bottom - rChild.top;
\r
6699 /* Get the Height and Width of the parent window */
\r
6700 GetWindowRect (hwndParent, &rParent);
\r
6701 wParent = rParent.right - rParent.left;
\r
6702 hParent = rParent.bottom - rParent.top;
\r
6704 /* Get the display limits */
\r
6705 hdc = GetDC (hwndChild);
\r
6706 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6707 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6708 ReleaseDC(hwndChild, hdc);
\r
6710 /* Calculate new X position, then adjust for screen */
\r
6711 xNew = rParent.left + ((wParent - wChild) /2);
\r
6714 } else if ((xNew+wChild) > wScreen) {
\r
6715 xNew = wScreen - wChild;
\r
6718 /* Calculate new Y position, then adjust for screen */
\r
6720 yNew = rParent.top + ((hParent - hChild) /2);
\r
6723 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6728 } else if ((yNew+hChild) > hScreen) {
\r
6729 yNew = hScreen - hChild;
\r
6732 /* Set it, and return */
\r
6733 return SetWindowPos (hwndChild, NULL,
\r
6734 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6737 /* Center one window over another */
\r
6738 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6740 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6743 /*---------------------------------------------------------------------------*\
\r
6745 * Startup Dialog functions
\r
6747 \*---------------------------------------------------------------------------*/
\r
6749 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6751 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6753 while (*cd != NULL) {
\r
6754 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6760 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6762 char buf1[ARG_MAX];
\r
6765 if (str[0] == '@') {
\r
6766 FILE* f = fopen(str + 1, "r");
\r
6768 DisplayFatalError(str + 1, errno, 2);
\r
6771 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6773 buf1[len] = NULLCHAR;
\r
6777 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6780 char buf[MSG_SIZ];
\r
6781 char *end = strchr(str, '\n');
\r
6782 if (end == NULL) return;
\r
6783 memcpy(buf, str, end - str);
\r
6784 buf[end - str] = NULLCHAR;
\r
6785 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6791 SetStartupDialogEnables(HWND hDlg)
\r
6793 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6794 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6795 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6796 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6797 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6798 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6799 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6800 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6801 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6802 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6803 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6804 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6805 IsDlgButtonChecked(hDlg, OPT_View));
\r
6809 QuoteForFilename(char *filename)
\r
6811 int dquote, space;
\r
6812 dquote = strchr(filename, '"') != NULL;
\r
6813 space = strchr(filename, ' ') != NULL;
\r
6814 if (dquote || space) {
\r
6826 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6828 char buf[MSG_SIZ];
\r
6831 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6832 q = QuoteForFilename(nthcp);
\r
6833 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6834 if (*nthdir != NULLCHAR) {
\r
6835 q = QuoteForFilename(nthdir);
\r
6836 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6838 if (*nthcp == NULLCHAR) {
\r
6839 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6840 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6841 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6842 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6847 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6849 char buf[MSG_SIZ];
\r
6853 switch (message) {
\r
6854 case WM_INITDIALOG:
\r
6855 /* Center the dialog */
\r
6856 CenterWindow (hDlg, GetDesktopWindow());
\r
6857 /* Initialize the dialog items */
\r
6858 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6859 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6860 firstChessProgramNames);
\r
6861 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6862 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6863 secondChessProgramNames);
\r
6864 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6865 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6866 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6867 if (*appData.icsHelper != NULLCHAR) {
\r
6868 char *q = QuoteForFilename(appData.icsHelper);
\r
6869 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6871 if (*appData.icsHost == NULLCHAR) {
\r
6872 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6873 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6874 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6875 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6876 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6879 if (appData.icsActive) {
\r
6880 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6882 else if (appData.noChessProgram) {
\r
6883 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6886 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6889 SetStartupDialogEnables(hDlg);
\r
6893 switch (LOWORD(wParam)) {
\r
6895 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6896 strcpy(buf, "/fcp=");
\r
6897 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6899 ParseArgs(StringGet, &p);
\r
6900 strcpy(buf, "/scp=");
\r
6901 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6903 ParseArgs(StringGet, &p);
\r
6904 appData.noChessProgram = FALSE;
\r
6905 appData.icsActive = FALSE;
\r
6906 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6907 strcpy(buf, "/ics /icshost=");
\r
6908 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6910 ParseArgs(StringGet, &p);
\r
6911 if (appData.zippyPlay) {
\r
6912 strcpy(buf, "/fcp=");
\r
6913 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6915 ParseArgs(StringGet, &p);
\r
6917 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6918 appData.noChessProgram = TRUE;
\r
6919 appData.icsActive = FALSE;
\r
6921 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6922 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6925 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6926 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6928 ParseArgs(StringGet, &p);
\r
6930 EndDialog(hDlg, TRUE);
\r
6937 case IDM_HELPCONTENTS:
\r
6938 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6939 MessageBox (GetFocus(),
\r
6940 "Unable to activate help",
\r
6941 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6946 SetStartupDialogEnables(hDlg);
\r
6954 /*---------------------------------------------------------------------------*\
\r
6956 * About box dialog functions
\r
6958 \*---------------------------------------------------------------------------*/
\r
6960 /* Process messages for "About" dialog box */
\r
6962 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6964 switch (message) {
\r
6965 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6966 /* Center the dialog over the application window */
\r
6967 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6968 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6972 case WM_COMMAND: /* message: received a command */
\r
6973 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6974 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6975 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6983 /*---------------------------------------------------------------------------*\
\r
6985 * Comment Dialog functions
\r
6987 \*---------------------------------------------------------------------------*/
\r
6990 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6992 static HANDLE hwndText = NULL;
\r
6993 int len, newSizeX, newSizeY, flags;
\r
6994 static int sizeX, sizeY;
\r
6999 switch (message) {
\r
7000 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7001 /* Initialize the dialog items */
\r
7002 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7003 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7004 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7005 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7006 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7007 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7008 SetWindowText(hDlg, commentTitle);
\r
7009 if (editComment) {
\r
7010 SetFocus(hwndText);
\r
7012 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7014 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7015 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7016 MAKELPARAM(FALSE, 0));
\r
7017 /* Size and position the dialog */
\r
7018 if (!commentDialog) {
\r
7019 commentDialog = hDlg;
\r
7020 flags = SWP_NOZORDER;
\r
7021 GetClientRect(hDlg, &rect);
\r
7022 sizeX = rect.right;
\r
7023 sizeY = rect.bottom;
\r
7024 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7025 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7026 WINDOWPLACEMENT wp;
\r
7027 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7028 wp.length = sizeof(WINDOWPLACEMENT);
\r
7030 wp.showCmd = SW_SHOW;
\r
7031 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7032 wp.rcNormalPosition.left = commentX;
\r
7033 wp.rcNormalPosition.right = commentX + commentW;
\r
7034 wp.rcNormalPosition.top = commentY;
\r
7035 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7036 SetWindowPlacement(hDlg, &wp);
\r
7038 GetClientRect(hDlg, &rect);
\r
7039 newSizeX = rect.right;
\r
7040 newSizeY = rect.bottom;
\r
7041 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7042 newSizeX, newSizeY);
\r
7049 case WM_COMMAND: /* message: received a command */
\r
7050 switch (LOWORD(wParam)) {
\r
7052 if (editComment) {
\r
7054 /* Read changed options from the dialog box */
\r
7055 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7056 len = GetWindowTextLength(hwndText);
\r
7057 str = (char *) malloc(len + 1);
\r
7058 GetWindowText(hwndText, str, len + 1);
\r
7067 ReplaceComment(commentIndex, str);
\r
7074 case OPT_CancelComment:
\r
7078 case OPT_ClearComment:
\r
7079 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7082 case OPT_EditComment:
\r
7083 EditCommentEvent();
\r
7092 newSizeX = LOWORD(lParam);
\r
7093 newSizeY = HIWORD(lParam);
\r
7094 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7099 case WM_GETMINMAXINFO:
\r
7100 /* Prevent resizing window too small */
\r
7101 mmi = (MINMAXINFO *) lParam;
\r
7102 mmi->ptMinTrackSize.x = 100;
\r
7103 mmi->ptMinTrackSize.y = 100;
\r
7110 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7115 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7117 if (str == NULL) str = "";
\r
7118 p = (char *) malloc(2 * strlen(str) + 2);
\r
7121 if (*str == '\n') *q++ = '\r';
\r
7125 if (commentText != NULL) free(commentText);
\r
7127 commentIndex = index;
\r
7128 commentTitle = title;
\r
7130 editComment = edit;
\r
7132 if (commentDialog) {
\r
7133 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7134 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7136 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7137 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7138 hwndMain, (DLGPROC)lpProc);
\r
7139 FreeProcInstance(lpProc);
\r
7141 commentDialogUp = TRUE;
\r
7145 /*---------------------------------------------------------------------------*\
\r
7147 * Type-in move dialog functions
\r
7149 \*---------------------------------------------------------------------------*/
\r
7152 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7154 char move[MSG_SIZ];
\r
7156 ChessMove moveType;
\r
7157 int fromX, fromY, toX, toY;
\r
7160 switch (message) {
\r
7161 case WM_INITDIALOG:
\r
7162 move[0] = (char) lParam;
\r
7163 move[1] = NULLCHAR;
\r
7164 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7165 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7166 SetWindowText(hInput, move);
\r
7168 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7172 switch (LOWORD(wParam)) {
\r
7174 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7175 { int n; Board board;
\r
7177 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7178 EditPositionPasteFEN(move);
\r
7179 EndDialog(hDlg, TRUE);
\r
7182 // [HGM] movenum: allow move number to be typed in any mode
\r
7183 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7184 currentMove = 2*n-1;
\r
7185 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7186 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7187 EndDialog(hDlg, TRUE);
\r
7188 DrawPosition(TRUE, boards[currentMove]);
\r
7189 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7190 else DisplayMessage("", "");
\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 commentDialogUp = 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