2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
291 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
292 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
293 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
294 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 int commentUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 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
1499 mfp->charset = DEFAULT_CHARSET;
\r
1500 q = strchr(p, 'c');
\r
1502 mfp->charset = (BYTE) atoi(q+1);
\r
1505 /* Color name parser.
\r
1506 X version accepts X color names, but this one
\r
1507 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1509 ParseColorName(char *name)
\r
1511 int red, green, blue, count;
\r
1512 char buf[MSG_SIZ];
\r
1514 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1516 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1517 &red, &green, &blue);
\r
1520 sprintf(buf, "Can't parse color name %s", name);
\r
1521 DisplayError(buf, 0);
\r
1522 return RGB(0, 0, 0);
\r
1524 return PALETTERGB(red, green, blue);
\r
1528 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1530 char *e = argValue;
\r
1534 if (*e == 'b') eff |= CFE_BOLD;
\r
1535 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1536 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1537 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1538 else if (*e == '#' || isdigit(*e)) break;
\r
1542 *color = ParseColorName(e);
\r
1547 ParseBoardSize(char *name)
\r
1549 BoardSize bs = SizeTiny;
\r
1550 while (sizeInfo[bs].name != NULL) {
\r
1551 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1554 ExitArgError("Unrecognized board size value", name);
\r
1555 return bs; /* not reached */
\r
1560 StringGet(void *getClosure)
\r
1562 char **p = (char **) getClosure;
\r
1567 FileGet(void *getClosure)
\r
1570 FILE* f = (FILE*) getClosure;
\r
1573 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1580 /* Parse settings file named "name". If file found, return the
\r
1581 full name in fullname and return TRUE; else return FALSE */
\r
1583 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1587 int ok; char buf[MSG_SIZ];
\r
1589 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1590 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1591 sprintf(buf, "%s.ini", name);
\r
1592 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1595 f = fopen(fullname, "r");
\r
1597 ParseArgs(FileGet, f);
\r
1606 ParseArgs(GetFunc get, void *cl)
\r
1608 char argName[ARG_MAX];
\r
1609 char argValue[ARG_MAX];
\r
1610 ArgDescriptor *ad;
\r
1619 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1620 if (ch == NULLCHAR) break;
\r
1622 /* Comment to end of line */
\r
1624 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1626 } else if (ch == '/' || ch == '-') {
\r
1629 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1630 ch != '\n' && ch != '\t') {
\r
1636 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1637 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1639 if (ad->argName == NULL)
\r
1640 ExitArgError("Unrecognized argument", argName);
\r
1642 } else if (ch == '@') {
\r
1643 /* Indirection file */
\r
1644 ad = &argDescriptorIndirection;
\r
1647 /* Positional argument */
\r
1648 ad = &argDescriptors[posarg++];
\r
1649 strcpy(argName, ad->argName);
\r
1652 if (ad->argType == ArgTrue) {
\r
1653 *(Boolean *) ad->argLoc = TRUE;
\r
1656 if (ad->argType == ArgFalse) {
\r
1657 *(Boolean *) ad->argLoc = FALSE;
\r
1661 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1662 if (ch == NULLCHAR || ch == '\n') {
\r
1663 ExitArgError("No value provided for argument", argName);
\r
1667 // Quoting with { }. No characters have to (or can) be escaped.
\r
1668 // Thus the string cannot contain a '}' character.
\r
1688 } else if (ch == '\'' || ch == '"') {
\r
1689 // Quoting with ' ' or " ", with \ as escape character.
\r
1690 // Inconvenient for long strings that may contain Windows filenames.
\r
1707 if (ch == start) {
\r
1716 if (ad->argType == ArgFilename
\r
1717 || ad->argType == ArgSettingsFilename) {
\r
1723 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1747 for (i = 0; i < 3; i++) {
\r
1748 if (ch >= '0' && ch <= '7') {
\r
1749 octval = octval*8 + (ch - '0');
\r
1756 *q++ = (char) octval;
\r
1767 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1774 switch (ad->argType) {
\r
1776 *(int *) ad->argLoc = atoi(argValue);
\r
1780 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1784 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1788 *(int *) ad->argLoc = atoi(argValue);
\r
1789 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1793 *(float *) ad->argLoc = (float) atof(argValue);
\r
1798 *(char **) ad->argLoc = strdup(argValue);
\r
1801 case ArgSettingsFilename:
\r
1803 char fullname[MSG_SIZ];
\r
1804 if (ParseSettingsFile(argValue, fullname)) {
\r
1805 if (ad->argLoc != NULL) {
\r
1806 *(char **) ad->argLoc = strdup(fullname);
\r
1809 if (ad->argLoc != NULL) {
\r
1811 ExitArgError("Failed to open indirection file", argValue);
\r
1818 switch (argValue[0]) {
\r
1821 *(Boolean *) ad->argLoc = TRUE;
\r
1825 *(Boolean *) ad->argLoc = FALSE;
\r
1828 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1834 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1837 case ArgAttribs: {
\r
1838 ColorClass cc = (ColorClass)ad->argLoc;
\r
1839 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1843 case ArgBoardSize:
\r
1844 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1848 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1851 case ArgCommSettings:
\r
1852 ParseCommSettings(argValue, &dcb);
\r
1856 ExitArgError("Unrecognized argument", argValue);
\r
1865 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1867 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1868 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1871 lf->lfEscapement = 0;
\r
1872 lf->lfOrientation = 0;
\r
1873 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1874 lf->lfItalic = mfp->italic;
\r
1875 lf->lfUnderline = mfp->underline;
\r
1876 lf->lfStrikeOut = mfp->strikeout;
\r
1877 lf->lfCharSet = mfp->charset;
\r
1878 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1879 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1880 lf->lfQuality = DEFAULT_QUALITY;
\r
1881 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1882 strcpy(lf->lfFaceName, mfp->faceName);
\r
1886 CreateFontInMF(MyFont *mf)
\r
1888 LFfromMFP(&mf->lf, &mf->mfp);
\r
1889 if (mf->hf) DeleteObject(mf->hf);
\r
1890 mf->hf = CreateFontIndirect(&mf->lf);
\r
1894 SetDefaultTextAttribs()
\r
1897 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1898 ParseAttribs(&textAttribs[cc].color,
\r
1899 &textAttribs[cc].effects,
\r
1900 defaultTextAttribs[cc]);
\r
1905 SetDefaultSounds()
\r
1909 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1910 textAttribs[cc].sound.name = strdup("");
\r
1911 textAttribs[cc].sound.data = NULL;
\r
1913 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1914 sounds[sc].name = strdup("");
\r
1915 sounds[sc].data = NULL;
\r
1917 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1925 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1926 MyLoadSound(&textAttribs[cc].sound);
\r
1928 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1929 MyLoadSound(&sounds[sc]);
\r
1934 InitAppData(LPSTR lpCmdLine)
\r
1937 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1940 programName = szAppName;
\r
1942 /* Initialize to defaults */
\r
1943 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1944 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1945 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1946 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1947 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1948 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1949 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1950 SetDefaultTextAttribs();
\r
1951 SetDefaultSounds();
\r
1952 appData.movesPerSession = MOVES_PER_SESSION;
\r
1953 appData.initString = INIT_STRING;
\r
1954 appData.secondInitString = INIT_STRING;
\r
1955 appData.firstComputerString = COMPUTER_STRING;
\r
1956 appData.secondComputerString = COMPUTER_STRING;
\r
1957 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1958 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1959 appData.firstPlaysBlack = FALSE;
\r
1960 appData.noChessProgram = FALSE;
\r
1961 chessProgram = FALSE;
\r
1962 appData.firstHost = FIRST_HOST;
\r
1963 appData.secondHost = SECOND_HOST;
\r
1964 appData.firstDirectory = FIRST_DIRECTORY;
\r
1965 appData.secondDirectory = SECOND_DIRECTORY;
\r
1966 appData.bitmapDirectory = "";
\r
1967 appData.remoteShell = REMOTE_SHELL;
\r
1968 appData.remoteUser = "";
\r
1969 appData.timeDelay = TIME_DELAY;
\r
1970 appData.timeControl = TIME_CONTROL;
\r
1971 appData.timeIncrement = TIME_INCREMENT;
\r
1972 appData.icsActive = FALSE;
\r
1973 appData.icsHost = "";
\r
1974 appData.icsPort = ICS_PORT;
\r
1975 appData.icsCommPort = ICS_COMM_PORT;
\r
1976 appData.icsLogon = ICS_LOGON;
\r
1977 appData.icsHelper = "";
\r
1978 appData.useTelnet = FALSE;
\r
1979 appData.telnetProgram = TELNET_PROGRAM;
\r
1980 appData.gateway = "";
\r
1981 appData.loadGameFile = "";
\r
1982 appData.loadGameIndex = 0;
\r
1983 appData.saveGameFile = "";
\r
1984 appData.autoSaveGames = FALSE;
\r
1985 appData.loadPositionFile = "";
\r
1986 appData.loadPositionIndex = 1;
\r
1987 appData.savePositionFile = "";
\r
1988 appData.matchMode = FALSE;
\r
1989 appData.matchGames = 0;
\r
1990 appData.monoMode = FALSE;
\r
1991 appData.debugMode = FALSE;
\r
1992 appData.clockMode = TRUE;
\r
1993 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1994 appData.Iconic = FALSE; /*unused*/
\r
1995 appData.searchTime = "";
\r
1996 appData.searchDepth = 0;
\r
1997 appData.showCoords = FALSE;
\r
1998 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1999 appData.autoCallFlag = FALSE;
\r
2000 appData.flipView = FALSE;
\r
2001 appData.autoFlipView = TRUE;
\r
2002 appData.cmailGameName = "";
\r
2003 appData.alwaysPromoteToQueen = FALSE;
\r
2004 appData.oldSaveStyle = FALSE;
\r
2005 appData.quietPlay = FALSE;
\r
2006 appData.showThinking = FALSE;
\r
2007 appData.ponderNextMove = TRUE;
\r
2008 appData.periodicUpdates = TRUE;
\r
2009 appData.popupExitMessage = TRUE;
\r
2010 appData.popupMoveErrors = FALSE;
\r
2011 appData.autoObserve = FALSE;
\r
2012 appData.autoComment = FALSE;
\r
2013 appData.animate = TRUE;
\r
2014 appData.animSpeed = 10;
\r
2015 appData.animateDragging = TRUE;
\r
2016 appData.highlightLastMove = TRUE;
\r
2017 appData.getMoveList = TRUE;
\r
2018 appData.testLegality = TRUE;
\r
2019 appData.premove = TRUE;
\r
2020 appData.premoveWhite = FALSE;
\r
2021 appData.premoveWhiteText = "";
\r
2022 appData.premoveBlack = FALSE;
\r
2023 appData.premoveBlackText = "";
\r
2024 appData.icsAlarm = TRUE;
\r
2025 appData.icsAlarmTime = 5000;
\r
2026 appData.autoRaiseBoard = TRUE;
\r
2027 appData.localLineEditing = TRUE;
\r
2028 appData.colorize = TRUE;
\r
2029 appData.reuseFirst = TRUE;
\r
2030 appData.reuseSecond = TRUE;
\r
2031 appData.blindfold = FALSE;
\r
2032 appData.icsEngineAnalyze = FALSE;
\r
2033 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2034 dcb.DCBlength = sizeof(DCB);
\r
2035 dcb.BaudRate = 9600;
\r
2036 dcb.fBinary = TRUE;
\r
2037 dcb.fParity = FALSE;
\r
2038 dcb.fOutxCtsFlow = FALSE;
\r
2039 dcb.fOutxDsrFlow = FALSE;
\r
2040 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2041 dcb.fDsrSensitivity = FALSE;
\r
2042 dcb.fTXContinueOnXoff = TRUE;
\r
2043 dcb.fOutX = FALSE;
\r
2045 dcb.fNull = FALSE;
\r
2046 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2047 dcb.fAbortOnError = FALSE;
\r
2049 dcb.Parity = SPACEPARITY;
\r
2050 dcb.StopBits = ONESTOPBIT;
\r
2051 settingsFileName = SETTINGS_FILE;
\r
2052 saveSettingsOnExit = TRUE;
\r
2053 boardX = CW_USEDEFAULT;
\r
2054 boardY = CW_USEDEFAULT;
\r
2055 analysisX = CW_USEDEFAULT;
\r
2056 analysisY = CW_USEDEFAULT;
\r
2057 analysisW = CW_USEDEFAULT;
\r
2058 analysisH = CW_USEDEFAULT;
\r
2059 commentX = CW_USEDEFAULT;
\r
2060 commentY = CW_USEDEFAULT;
\r
2061 commentW = CW_USEDEFAULT;
\r
2062 commentH = CW_USEDEFAULT;
\r
2063 editTagsX = CW_USEDEFAULT;
\r
2064 editTagsY = CW_USEDEFAULT;
\r
2065 editTagsW = CW_USEDEFAULT;
\r
2066 editTagsH = CW_USEDEFAULT;
\r
2067 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2068 icsNames = ICS_NAMES;
\r
2069 firstChessProgramNames = FCP_NAMES;
\r
2070 secondChessProgramNames = SCP_NAMES;
\r
2071 appData.initialMode = "";
\r
2072 appData.variant = "normal";
\r
2073 appData.firstProtocolVersion = PROTOVER;
\r
2074 appData.secondProtocolVersion = PROTOVER;
\r
2075 appData.showButtonBar = TRUE;
\r
2077 /* [AS] New properties (see comments in header file) */
\r
2078 appData.firstScoreIsAbsolute = FALSE;
\r
2079 appData.secondScoreIsAbsolute = FALSE;
\r
2080 appData.saveExtendedInfoInPGN = FALSE;
\r
2081 appData.hideThinkingFromHuman = FALSE;
\r
2082 appData.liteBackTextureFile = "";
\r
2083 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2084 appData.darkBackTextureFile = "";
\r
2085 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2086 appData.renderPiecesWithFont = "";
\r
2087 appData.fontToPieceTable = "";
\r
2088 appData.fontBackColorWhite = 0;
\r
2089 appData.fontForeColorWhite = 0;
\r
2090 appData.fontBackColorBlack = 0;
\r
2091 appData.fontForeColorBlack = 0;
\r
2092 appData.fontPieceSize = 80;
\r
2093 appData.overrideLineGap = 1;
\r
2094 appData.adjudicateLossThreshold = 0;
\r
2095 appData.delayBeforeQuit = 0;
\r
2096 appData.delayAfterQuit = 0;
\r
2097 appData.nameOfDebugFile = "winboard.debug";
\r
2098 appData.pgnEventHeader = "Computer Chess Game";
\r
2099 appData.defaultFrcPosition = -1;
\r
2100 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2101 appData.saveOutOfBookInfo = TRUE;
\r
2102 appData.showEvalInMoveHistory = TRUE;
\r
2103 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2104 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2105 appData.highlightMoveWithArrow = FALSE;
\r
2106 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2107 appData.useStickyWindows = TRUE;
\r
2108 appData.adjudicateDrawMoves = 0;
\r
2109 appData.autoDisplayComment = TRUE;
\r
2110 appData.autoDisplayTags = TRUE;
\r
2111 appData.firstIsUCI = FALSE;
\r
2112 appData.secondIsUCI = FALSE;
\r
2113 appData.firstHasOwnBookUCI = TRUE;
\r
2114 appData.secondHasOwnBookUCI = TRUE;
\r
2115 appData.polyglotDir = "";
\r
2116 appData.usePolyglotBook = FALSE;
\r
2117 appData.polyglotBook = "";
\r
2118 appData.defaultHashSize = 64;
\r
2119 appData.defaultCacheSizeEGTB = 4;
\r
2120 appData.defaultPathEGTB = "c:\\egtb";
\r
2121 appData.firstOptions = "";
\r
2122 appData.secondOptions = "";
\r
2124 InitWindowPlacement( &wpGameList );
\r
2125 InitWindowPlacement( &wpMoveHistory );
\r
2126 InitWindowPlacement( &wpEvalGraph );
\r
2127 InitWindowPlacement( &wpEngineOutput );
\r
2128 InitWindowPlacement( &wpConsole );
\r
2130 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2131 appData.NrFiles = -1;
\r
2132 appData.NrRanks = -1;
\r
2133 appData.holdingsSize = -1;
\r
2134 appData.testClaims = FALSE;
\r
2135 appData.checkMates = FALSE;
\r
2136 appData.materialDraws= FALSE;
\r
2137 appData.trivialDraws = FALSE;
\r
2138 appData.ruleMoves = 51;
\r
2139 appData.drawRepeats = 6;
\r
2140 appData.matchPause = 10000;
\r
2141 appData.alphaRank = FALSE;
\r
2142 appData.allWhite = FALSE;
\r
2143 appData.upsideDown = FALSE;
\r
2144 appData.serverPause = 15;
\r
2145 appData.serverMovesName = NULL;
\r
2146 appData.suppressLoadMoves = FALSE;
\r
2147 appData.firstTimeOdds = 1;
\r
2148 appData.secondTimeOdds = 1;
\r
2149 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2150 appData.secondAccumulateTC = 1;
\r
2151 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2152 appData.secondNPS = -1;
\r
2153 appData.engineComments = 1;
\r
2154 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2155 appData.egtFormats = "";
\r
2158 appData.zippyTalk = ZIPPY_TALK;
\r
2159 appData.zippyPlay = ZIPPY_PLAY;
\r
2160 appData.zippyLines = ZIPPY_LINES;
\r
2161 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2162 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2163 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2164 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2165 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2166 appData.zippyUseI = ZIPPY_USE_I;
\r
2167 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2168 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2169 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2170 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2171 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2172 appData.zippyAbort = ZIPPY_ABORT;
\r
2173 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2174 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2175 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2178 /* Point font array elements to structures and
\r
2179 parse default font names */
\r
2180 for (i=0; i<NUM_FONTS; i++) {
\r
2181 for (j=0; j<NUM_SIZES; j++) {
\r
2182 font[j][i] = &fontRec[j][i];
\r
2183 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2187 /* Parse default settings file if any */
\r
2188 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2189 settingsFileName = strdup(buf);
\r
2192 /* Parse command line */
\r
2193 ParseArgs(StringGet, &lpCmdLine);
\r
2195 /* [HGM] make sure board size is acceptable */
\r
2196 if(appData.NrFiles > BOARD_SIZE ||
\r
2197 appData.NrRanks > BOARD_SIZE )
\r
2198 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2200 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2201 * with options from the command line, we now make an even higher priority
\r
2202 * overrule by WB options attached to the engine command line. This so that
\r
2203 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2206 if(appData.firstChessProgram != NULL) {
\r
2207 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2208 static char *f = "first";
\r
2209 char buf[MSG_SIZ], *q = buf;
\r
2210 if(p != NULL) { // engine command line contains WinBoard options
\r
2211 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2212 ParseArgs(StringGet, &q);
\r
2213 p[-1] = 0; // cut them offengine command line
\r
2216 // now do same for second chess program
\r
2217 if(appData.secondChessProgram != NULL) {
\r
2218 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2219 static char *s = "second";
\r
2220 char buf[MSG_SIZ], *q = buf;
\r
2221 if(p != NULL) { // engine command line contains WinBoard options
\r
2222 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2223 ParseArgs(StringGet, &q);
\r
2224 p[-1] = 0; // cut them offengine command line
\r
2229 /* Propagate options that affect others */
\r
2230 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2231 if (appData.icsActive || appData.noChessProgram) {
\r
2232 chessProgram = FALSE; /* not local chess program mode */
\r
2235 /* Open startup dialog if needed */
\r
2236 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2237 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2238 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2239 *appData.secondChessProgram == NULLCHAR))) {
\r
2242 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2243 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2244 FreeProcInstance(lpProc);
\r
2247 /* Make sure save files land in the right (?) directory */
\r
2248 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2249 appData.saveGameFile = strdup(buf);
\r
2251 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2252 appData.savePositionFile = strdup(buf);
\r
2255 /* Finish initialization for fonts and sounds */
\r
2256 for (i=0; i<NUM_FONTS; i++) {
\r
2257 for (j=0; j<NUM_SIZES; j++) {
\r
2258 CreateFontInMF(font[j][i]);
\r
2261 /* xboard, and older WinBoards, controlled the move sound with the
\r
2262 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2263 always turn the option on (so that the backend will call us),
\r
2264 then let the user turn the sound off by setting it to silence if
\r
2265 desired. To accommodate old winboard.ini files saved by old
\r
2266 versions of WinBoard, we also turn off the sound if the option
\r
2267 was initially set to false. */
\r
2268 if (!appData.ringBellAfterMoves) {
\r
2269 sounds[(int)SoundMove].name = strdup("");
\r
2270 appData.ringBellAfterMoves = TRUE;
\r
2272 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2273 SetCurrentDirectory(installDir);
\r
2275 SetCurrentDirectory(currDir);
\r
2277 p = icsTextMenuString;
\r
2278 if (p[0] == '@') {
\r
2279 FILE* f = fopen(p + 1, "r");
\r
2281 DisplayFatalError(p + 1, errno, 2);
\r
2284 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2286 buf[i] = NULLCHAR;
\r
2289 ParseIcsTextMenu(strdup(p));
\r
2296 HMENU hmenu = GetMenu(hwndMain);
\r
2298 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2299 MF_BYCOMMAND|((appData.icsActive &&
\r
2300 *appData.icsCommPort != NULLCHAR) ?
\r
2301 MF_ENABLED : MF_GRAYED));
\r
2302 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2303 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2304 MF_CHECKED : MF_UNCHECKED));
\r
2309 SaveSettings(char* name)
\r
2312 ArgDescriptor *ad;
\r
2313 WINDOWPLACEMENT wp;
\r
2314 char dir[MSG_SIZ];
\r
2316 if (!hwndMain) return;
\r
2318 GetCurrentDirectory(MSG_SIZ, dir);
\r
2319 SetCurrentDirectory(installDir);
\r
2320 f = fopen(name, "w");
\r
2321 SetCurrentDirectory(dir);
\r
2323 DisplayError(name, errno);
\r
2326 fprintf(f, ";\n");
\r
2327 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2328 fprintf(f, ";\n");
\r
2329 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2330 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2331 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2332 fprintf(f, ";\n");
\r
2334 wp.length = sizeof(WINDOWPLACEMENT);
\r
2335 GetWindowPlacement(hwndMain, &wp);
\r
2336 boardX = wp.rcNormalPosition.left;
\r
2337 boardY = wp.rcNormalPosition.top;
\r
2339 if (hwndConsole) {
\r
2340 GetWindowPlacement(hwndConsole, &wp);
\r
2341 wpConsole.x = wp.rcNormalPosition.left;
\r
2342 wpConsole.y = wp.rcNormalPosition.top;
\r
2343 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (analysisDialog) {
\r
2348 GetWindowPlacement(analysisDialog, &wp);
\r
2349 analysisX = wp.rcNormalPosition.left;
\r
2350 analysisY = wp.rcNormalPosition.top;
\r
2351 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 if (commentDialog) {
\r
2356 GetWindowPlacement(commentDialog, &wp);
\r
2357 commentX = wp.rcNormalPosition.left;
\r
2358 commentY = wp.rcNormalPosition.top;
\r
2359 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2360 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2363 if (editTagsDialog) {
\r
2364 GetWindowPlacement(editTagsDialog, &wp);
\r
2365 editTagsX = wp.rcNormalPosition.left;
\r
2366 editTagsY = wp.rcNormalPosition.top;
\r
2367 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2368 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2371 if (gameListDialog) {
\r
2372 GetWindowPlacement(gameListDialog, &wp);
\r
2373 wpGameList.x = wp.rcNormalPosition.left;
\r
2374 wpGameList.y = wp.rcNormalPosition.top;
\r
2375 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2376 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2379 /* [AS] Move history */
\r
2380 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2382 if( moveHistoryDialog ) {
\r
2383 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2384 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2385 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2386 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2387 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2390 /* [AS] Eval graph */
\r
2391 wpEvalGraph.visible = EvalGraphIsUp();
\r
2393 if( evalGraphDialog ) {
\r
2394 GetWindowPlacement(evalGraphDialog, &wp);
\r
2395 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2396 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2397 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2398 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2401 /* [AS] Engine output */
\r
2402 wpEngineOutput.visible = EngineOutputIsUp();
\r
2404 if( engineOutputDialog ) {
\r
2405 GetWindowPlacement(engineOutputDialog, &wp);
\r
2406 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2407 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2408 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2409 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2412 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2413 if (!ad->save) continue;
\r
2414 switch (ad->argType) {
\r
2417 char *p = *(char **)ad->argLoc;
\r
2418 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2419 /* Quote multiline values or \-containing values
\r
2420 with { } if possible */
\r
2421 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2423 /* Else quote with " " */
\r
2424 fprintf(f, "/%s=\"", ad->argName);
\r
2426 if (*p == '\n') fprintf(f, "\n");
\r
2427 else if (*p == '\r') fprintf(f, "\\r");
\r
2428 else if (*p == '\t') fprintf(f, "\\t");
\r
2429 else if (*p == '\b') fprintf(f, "\\b");
\r
2430 else if (*p == '\f') fprintf(f, "\\f");
\r
2431 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2432 else if (*p == '\"') fprintf(f, "\\\"");
\r
2433 else if (*p == '\\') fprintf(f, "\\\\");
\r
2437 fprintf(f, "\"\n");
\r
2443 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2446 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2449 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2452 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2455 fprintf(f, "/%s=%s\n", ad->argName,
\r
2456 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2459 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2462 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2466 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2467 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2468 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2473 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2474 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2475 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2476 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2477 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2478 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2479 (ta->effects) ? " " : "",
\r
2480 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2484 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2485 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2487 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2490 case ArgBoardSize:
\r
2491 fprintf(f, "/%s=%s\n", ad->argName,
\r
2492 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2497 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2498 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2499 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2500 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2501 ad->argName, mfp->faceName, mfp->pointSize,
\r
2502 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2503 mfp->bold ? "b" : "",
\r
2504 mfp->italic ? "i" : "",
\r
2505 mfp->underline ? "u" : "",
\r
2506 mfp->strikeout ? "s" : "",
\r
2507 (int)mfp->charset);
\r
2511 case ArgCommSettings:
\r
2512 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2514 case ArgSettingsFilename: ;
\r
2522 /*---------------------------------------------------------------------------*\
\r
2524 * GDI board drawing routines
\r
2526 \*---------------------------------------------------------------------------*/
\r
2528 /* [AS] Draw square using background texture */
\r
2529 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2534 return; /* Should never happen! */
\r
2537 SetGraphicsMode( dst, GM_ADVANCED );
\r
2544 /* X reflection */
\r
2549 x.eDx = (FLOAT) dw + dx - 1;
\r
2552 SetWorldTransform( dst, &x );
\r
2555 /* Y reflection */
\r
2561 x.eDy = (FLOAT) dh + dy - 1;
\r
2563 SetWorldTransform( dst, &x );
\r
2571 x.eDx = (FLOAT) dx;
\r
2572 x.eDy = (FLOAT) dy;
\r
2575 SetWorldTransform( dst, &x );
\r
2579 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2587 SetWorldTransform( dst, &x );
\r
2589 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2592 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2594 PM_WP = (int) WhitePawn,
\r
2595 PM_WN = (int) WhiteKnight,
\r
2596 PM_WB = (int) WhiteBishop,
\r
2597 PM_WR = (int) WhiteRook,
\r
2598 PM_WQ = (int) WhiteQueen,
\r
2599 PM_WF = (int) WhiteFerz,
\r
2600 PM_WW = (int) WhiteWazir,
\r
2601 PM_WE = (int) WhiteAlfil,
\r
2602 PM_WM = (int) WhiteMan,
\r
2603 PM_WO = (int) WhiteCannon,
\r
2604 PM_WU = (int) WhiteUnicorn,
\r
2605 PM_WH = (int) WhiteNightrider,
\r
2606 PM_WA = (int) WhiteAngel,
\r
2607 PM_WC = (int) WhiteMarshall,
\r
2608 PM_WAB = (int) WhiteCardinal,
\r
2609 PM_WD = (int) WhiteDragon,
\r
2610 PM_WL = (int) WhiteLance,
\r
2611 PM_WS = (int) WhiteCobra,
\r
2612 PM_WV = (int) WhiteFalcon,
\r
2613 PM_WSG = (int) WhiteSilver,
\r
2614 PM_WG = (int) WhiteGrasshopper,
\r
2615 PM_WK = (int) WhiteKing,
\r
2616 PM_BP = (int) BlackPawn,
\r
2617 PM_BN = (int) BlackKnight,
\r
2618 PM_BB = (int) BlackBishop,
\r
2619 PM_BR = (int) BlackRook,
\r
2620 PM_BQ = (int) BlackQueen,
\r
2621 PM_BF = (int) BlackFerz,
\r
2622 PM_BW = (int) BlackWazir,
\r
2623 PM_BE = (int) BlackAlfil,
\r
2624 PM_BM = (int) BlackMan,
\r
2625 PM_BO = (int) BlackCannon,
\r
2626 PM_BU = (int) BlackUnicorn,
\r
2627 PM_BH = (int) BlackNightrider,
\r
2628 PM_BA = (int) BlackAngel,
\r
2629 PM_BC = (int) BlackMarshall,
\r
2630 PM_BG = (int) BlackGrasshopper,
\r
2631 PM_BAB = (int) BlackCardinal,
\r
2632 PM_BD = (int) BlackDragon,
\r
2633 PM_BL = (int) BlackLance,
\r
2634 PM_BS = (int) BlackCobra,
\r
2635 PM_BV = (int) BlackFalcon,
\r
2636 PM_BSG = (int) BlackSilver,
\r
2637 PM_BK = (int) BlackKing
\r
2640 static HFONT hPieceFont = NULL;
\r
2641 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2642 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2643 static int fontBitmapSquareSize = 0;
\r
2644 static char pieceToFontChar[(int) EmptySquare] =
\r
2645 { 'p', 'n', 'b', 'r', 'q',
\r
2646 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2647 'k', 'o', 'm', 'v', 't', 'w',
\r
2648 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2651 extern BOOL SetCharTable( char *table, const char * map );
\r
2652 /* [HGM] moved to backend.c */
\r
2654 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2657 BYTE r1 = GetRValue( color );
\r
2658 BYTE g1 = GetGValue( color );
\r
2659 BYTE b1 = GetBValue( color );
\r
2665 /* Create a uniform background first */
\r
2666 hbrush = CreateSolidBrush( color );
\r
2667 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2668 FillRect( hdc, &rc, hbrush );
\r
2669 DeleteObject( hbrush );
\r
2672 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2673 int steps = squareSize / 2;
\r
2676 for( i=0; i<steps; i++ ) {
\r
2677 BYTE r = r1 - (r1-r2) * i / steps;
\r
2678 BYTE g = g1 - (g1-g2) * i / steps;
\r
2679 BYTE b = b1 - (b1-b2) * i / steps;
\r
2681 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2682 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2683 FillRect( hdc, &rc, hbrush );
\r
2684 DeleteObject(hbrush);
\r
2687 else if( mode == 2 ) {
\r
2688 /* Diagonal gradient, good more or less for every piece */
\r
2689 POINT triangle[3];
\r
2690 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2691 HBRUSH hbrush_old;
\r
2692 int steps = squareSize;
\r
2695 triangle[0].x = squareSize - steps;
\r
2696 triangle[0].y = squareSize;
\r
2697 triangle[1].x = squareSize;
\r
2698 triangle[1].y = squareSize;
\r
2699 triangle[2].x = squareSize;
\r
2700 triangle[2].y = squareSize - steps;
\r
2702 for( i=0; i<steps; i++ ) {
\r
2703 BYTE r = r1 - (r1-r2) * i / steps;
\r
2704 BYTE g = g1 - (g1-g2) * i / steps;
\r
2705 BYTE b = b1 - (b1-b2) * i / steps;
\r
2707 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2708 hbrush_old = SelectObject( hdc, hbrush );
\r
2709 Polygon( hdc, triangle, 3 );
\r
2710 SelectObject( hdc, hbrush_old );
\r
2711 DeleteObject(hbrush);
\r
2716 SelectObject( hdc, hpen );
\r
2721 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2722 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2723 piece: follow the steps as explained below.
\r
2725 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2729 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2733 int backColor = whitePieceColor;
\r
2734 int foreColor = blackPieceColor;
\r
2736 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2737 backColor = appData.fontBackColorWhite;
\r
2738 foreColor = appData.fontForeColorWhite;
\r
2740 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2741 backColor = appData.fontBackColorBlack;
\r
2742 foreColor = appData.fontForeColorBlack;
\r
2746 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2748 hbm_old = SelectObject( hdc, hbm );
\r
2752 rc.right = squareSize;
\r
2753 rc.bottom = squareSize;
\r
2755 /* Step 1: background is now black */
\r
2756 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2758 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2760 pt.x = (squareSize - sz.cx) / 2;
\r
2761 pt.y = (squareSize - sz.cy) / 2;
\r
2763 SetBkMode( hdc, TRANSPARENT );
\r
2764 SetTextColor( hdc, chroma );
\r
2765 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2766 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2768 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2769 /* Step 3: the area outside the piece is filled with white */
\r
2770 // FloodFill( hdc, 0, 0, chroma );
\r
2771 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2772 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2773 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2774 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2775 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2777 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2778 but if the start point is not inside the piece we're lost!
\r
2779 There should be a better way to do this... if we could create a region or path
\r
2780 from the fill operation we would be fine for example.
\r
2782 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2783 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2785 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2786 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2787 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2789 SelectObject( dc2, bm2 );
\r
2790 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2791 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2792 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2793 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2794 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2797 DeleteObject( bm2 );
\r
2800 SetTextColor( hdc, 0 );
\r
2802 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2803 draw the piece again in black for safety.
\r
2805 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2807 SelectObject( hdc, hbm_old );
\r
2809 if( hPieceMask[index] != NULL ) {
\r
2810 DeleteObject( hPieceMask[index] );
\r
2813 hPieceMask[index] = hbm;
\r
2816 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2818 SelectObject( hdc, hbm );
\r
2821 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2822 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2823 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2825 SelectObject( dc1, hPieceMask[index] );
\r
2826 SelectObject( dc2, bm2 );
\r
2827 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2828 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2831 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2832 the piece background and deletes (makes transparent) the rest.
\r
2833 Thanks to that mask, we are free to paint the background with the greates
\r
2834 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2835 We use this, to make gradients and give the pieces a "roundish" look.
\r
2837 SetPieceBackground( hdc, backColor, 2 );
\r
2838 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2842 DeleteObject( bm2 );
\r
2845 SetTextColor( hdc, foreColor );
\r
2846 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2848 SelectObject( hdc, hbm_old );
\r
2850 if( hPieceFace[index] != NULL ) {
\r
2851 DeleteObject( hPieceFace[index] );
\r
2854 hPieceFace[index] = hbm;
\r
2857 static int TranslatePieceToFontPiece( int piece )
\r
2887 case BlackMarshall:
\r
2891 case BlackNightrider:
\r
2897 case BlackUnicorn:
\r
2901 case BlackGrasshopper:
\r
2913 case BlackCardinal:
\r
2920 case WhiteMarshall:
\r
2924 case WhiteNightrider:
\r
2930 case WhiteUnicorn:
\r
2934 case WhiteGrasshopper:
\r
2946 case WhiteCardinal:
\r
2955 void CreatePiecesFromFont()
\r
2958 HDC hdc_window = NULL;
\r
2964 if( fontBitmapSquareSize < 0 ) {
\r
2965 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2969 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2970 fontBitmapSquareSize = -1;
\r
2974 if( fontBitmapSquareSize != squareSize ) {
\r
2975 hdc_window = GetDC( hwndMain );
\r
2976 hdc = CreateCompatibleDC( hdc_window );
\r
2978 if( hPieceFont != NULL ) {
\r
2979 DeleteObject( hPieceFont );
\r
2982 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2983 hPieceMask[i] = NULL;
\r
2984 hPieceFace[i] = NULL;
\r
2990 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2991 fontHeight = appData.fontPieceSize;
\r
2994 fontHeight = (fontHeight * squareSize) / 100;
\r
2996 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2998 lf.lfEscapement = 0;
\r
2999 lf.lfOrientation = 0;
\r
3000 lf.lfWeight = FW_NORMAL;
\r
3002 lf.lfUnderline = 0;
\r
3003 lf.lfStrikeOut = 0;
\r
3004 lf.lfCharSet = DEFAULT_CHARSET;
\r
3005 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3006 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3007 lf.lfQuality = PROOF_QUALITY;
\r
3008 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3009 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3010 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3012 hPieceFont = CreateFontIndirect( &lf );
\r
3014 if( hPieceFont == NULL ) {
\r
3015 fontBitmapSquareSize = -2;
\r
3018 /* Setup font-to-piece character table */
\r
3019 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3020 /* No (or wrong) global settings, try to detect the font */
\r
3021 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3023 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3025 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3026 /* DiagramTT* family */
\r
3027 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3029 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3030 /* Fairy symbols */
\r
3031 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3033 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3034 /* Good Companion (Some characters get warped as literal :-( */
\r
3035 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3036 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3037 SetCharTable(pieceToFontChar, s);
\r
3040 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3041 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3045 /* Create bitmaps */
\r
3046 hfont_old = SelectObject( hdc, hPieceFont );
\r
3047 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3048 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3051 SelectObject( hdc, hfont_old );
\r
3053 fontBitmapSquareSize = squareSize;
\r
3057 if( hdc != NULL ) {
\r
3061 if( hdc_window != NULL ) {
\r
3062 ReleaseDC( hwndMain, hdc_window );
\r
3067 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3071 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3072 if (gameInfo.event &&
\r
3073 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3074 strcmp(name, "k80s") == 0) {
\r
3075 strcpy(name, "tim");
\r
3077 return LoadBitmap(hinst, name);
\r
3081 /* Insert a color into the program's logical palette
\r
3082 structure. This code assumes the given color is
\r
3083 the result of the RGB or PALETTERGB macro, and it
\r
3084 knows how those macros work (which is documented).
\r
3087 InsertInPalette(COLORREF color)
\r
3089 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3091 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3092 DisplayFatalError("Too many colors", 0, 1);
\r
3093 pLogPal->palNumEntries--;
\r
3097 pe->peFlags = (char) 0;
\r
3098 pe->peRed = (char) (0xFF & color);
\r
3099 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3100 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3106 InitDrawingColors()
\r
3108 if (pLogPal == NULL) {
\r
3109 /* Allocate enough memory for a logical palette with
\r
3110 * PALETTESIZE entries and set the size and version fields
\r
3111 * of the logical palette structure.
\r
3113 pLogPal = (NPLOGPALETTE)
\r
3114 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3115 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3116 pLogPal->palVersion = 0x300;
\r
3118 pLogPal->palNumEntries = 0;
\r
3120 InsertInPalette(lightSquareColor);
\r
3121 InsertInPalette(darkSquareColor);
\r
3122 InsertInPalette(whitePieceColor);
\r
3123 InsertInPalette(blackPieceColor);
\r
3124 InsertInPalette(highlightSquareColor);
\r
3125 InsertInPalette(premoveHighlightColor);
\r
3127 /* create a logical color palette according the information
\r
3128 * in the LOGPALETTE structure.
\r
3130 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3132 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3133 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3134 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3135 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3136 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3137 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3138 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3139 /* [AS] Force rendering of the font-based pieces */
\r
3140 if( fontBitmapSquareSize > 0 ) {
\r
3141 fontBitmapSquareSize = 0;
\r
3147 BoardWidth(int boardSize, int n)
\r
3148 { /* [HGM] argument n added to allow different width and height */
\r
3149 int lineGap = sizeInfo[boardSize].lineGap;
\r
3151 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3152 lineGap = appData.overrideLineGap;
\r
3155 return (n + 1) * lineGap +
\r
3156 n * sizeInfo[boardSize].squareSize;
\r
3159 /* Respond to board resize by dragging edge */
\r
3161 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3163 BoardSize newSize = NUM_SIZES - 1;
\r
3164 static int recurse = 0;
\r
3165 if (IsIconic(hwndMain)) return;
\r
3166 if (recurse > 0) return;
\r
3168 while (newSize > 0) {
\r
3169 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3170 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3171 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3174 boardSize = newSize;
\r
3175 InitDrawingSizes(boardSize, flags);
\r
3182 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3184 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3185 ChessSquare piece;
\r
3186 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3188 SIZE clockSize, messageSize;
\r
3190 char buf[MSG_SIZ];
\r
3192 HMENU hmenu = GetMenu(hwndMain);
\r
3193 RECT crect, wrect, oldRect;
\r
3195 LOGBRUSH logbrush;
\r
3197 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3198 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3200 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3201 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3203 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3204 oldRect.top = boardY;
\r
3205 oldRect.right = boardX + winWidth;
\r
3206 oldRect.bottom = boardY + winHeight;
\r
3208 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3209 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3210 squareSize = sizeInfo[boardSize].squareSize;
\r
3211 lineGap = sizeInfo[boardSize].lineGap;
\r
3212 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3214 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3215 lineGap = appData.overrideLineGap;
\r
3218 if (tinyLayout != oldTinyLayout) {
\r
3219 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3221 style &= ~WS_SYSMENU;
\r
3222 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3223 "&Minimize\tCtrl+F4");
\r
3225 style |= WS_SYSMENU;
\r
3226 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3228 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3230 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3231 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3232 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3234 DrawMenuBar(hwndMain);
\r
3237 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3238 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3240 /* Get text area sizes */
\r
3241 hdc = GetDC(hwndMain);
\r
3242 if (appData.clockMode) {
\r
3243 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3245 sprintf(buf, "White");
\r
3247 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3248 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3249 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3250 str = "We only care about the height here";
\r
3251 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3252 SelectObject(hdc, oldFont);
\r
3253 ReleaseDC(hwndMain, hdc);
\r
3255 /* Compute where everything goes */
\r
3256 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3257 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3258 logoHeight = 2*clockSize.cy;
\r
3259 leftLogoRect.left = OUTER_MARGIN;
\r
3260 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3261 leftLogoRect.top = OUTER_MARGIN;
\r
3262 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3264 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3265 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3266 rightLogoRect.top = OUTER_MARGIN;
\r
3267 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3270 whiteRect.left = leftLogoRect.right;
\r
3271 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3272 whiteRect.top = OUTER_MARGIN;
\r
3273 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3275 blackRect.right = rightLogoRect.left;
\r
3276 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3277 blackRect.top = whiteRect.top;
\r
3278 blackRect.bottom = whiteRect.bottom;
\r
3280 whiteRect.left = OUTER_MARGIN;
\r
3281 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3282 whiteRect.top = OUTER_MARGIN;
\r
3283 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3285 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3286 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3287 blackRect.top = whiteRect.top;
\r
3288 blackRect.bottom = whiteRect.bottom;
\r
3291 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3292 if (appData.showButtonBar) {
\r
3293 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3294 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3296 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3298 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3299 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3301 boardRect.left = OUTER_MARGIN;
\r
3302 boardRect.right = boardRect.left + boardWidth;
\r
3303 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3304 boardRect.bottom = boardRect.top + boardHeight;
\r
3306 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3307 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3308 oldBoardSize = boardSize;
\r
3309 oldTinyLayout = tinyLayout;
\r
3310 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3311 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3312 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3313 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3314 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3315 winHeight = winH; // without disturbing window attachments
\r
3316 GetWindowRect(hwndMain, &wrect);
\r
3317 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3318 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3320 // [HGM] placement: let attached windows follow size change.
\r
3321 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3322 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3323 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3324 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3325 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3327 /* compensate if menu bar wrapped */
\r
3328 GetClientRect(hwndMain, &crect);
\r
3329 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3330 winHeight += offby;
\r
3332 case WMSZ_TOPLEFT:
\r
3333 SetWindowPos(hwndMain, NULL,
\r
3334 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3335 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3338 case WMSZ_TOPRIGHT:
\r
3340 SetWindowPos(hwndMain, NULL,
\r
3341 wrect.left, wrect.bottom - winHeight,
\r
3342 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3345 case WMSZ_BOTTOMLEFT:
\r
3347 SetWindowPos(hwndMain, NULL,
\r
3348 wrect.right - winWidth, wrect.top,
\r
3349 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3352 case WMSZ_BOTTOMRIGHT:
\r
3356 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3357 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3362 for (i = 0; i < N_BUTTONS; i++) {
\r
3363 if (buttonDesc[i].hwnd != NULL) {
\r
3364 DestroyWindow(buttonDesc[i].hwnd);
\r
3365 buttonDesc[i].hwnd = NULL;
\r
3367 if (appData.showButtonBar) {
\r
3368 buttonDesc[i].hwnd =
\r
3369 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3370 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3371 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3372 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3373 (HMENU) buttonDesc[i].id,
\r
3374 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3376 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3377 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3378 MAKELPARAM(FALSE, 0));
\r
3380 if (buttonDesc[i].id == IDM_Pause)
\r
3381 hwndPause = buttonDesc[i].hwnd;
\r
3382 buttonDesc[i].wndproc = (WNDPROC)
\r
3383 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3386 if (gridPen != NULL) DeleteObject(gridPen);
\r
3387 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3388 if (premovePen != NULL) DeleteObject(premovePen);
\r
3389 if (lineGap != 0) {
\r
3390 logbrush.lbStyle = BS_SOLID;
\r
3391 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3393 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3394 lineGap, &logbrush, 0, NULL);
\r
3395 logbrush.lbColor = highlightSquareColor;
\r
3397 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3398 lineGap, &logbrush, 0, NULL);
\r
3400 logbrush.lbColor = premoveHighlightColor;
\r
3402 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3403 lineGap, &logbrush, 0, NULL);
\r
3405 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3406 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3407 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3408 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3409 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3410 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3411 BOARD_WIDTH * (squareSize + lineGap);
\r
3412 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3414 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3415 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3416 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3417 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3418 lineGap / 2 + (i * (squareSize + lineGap));
\r
3419 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3420 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3421 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3425 /* [HGM] Licensing requirement */
\r
3427 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3430 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3432 GothicPopUp( "", VariantNormal);
\r
3435 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3437 /* Load piece bitmaps for this board size */
\r
3438 for (i=0; i<=2; i++) {
\r
3439 for (piece = WhitePawn;
\r
3440 (int) piece < (int) BlackPawn;
\r
3441 piece = (ChessSquare) ((int) piece + 1)) {
\r
3442 if (pieceBitmap[i][piece] != NULL)
\r
3443 DeleteObject(pieceBitmap[i][piece]);
\r
3447 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3448 // Orthodox Chess pieces
\r
3449 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3450 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3451 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3452 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3453 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3454 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3455 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3456 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3457 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3458 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3459 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3460 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3461 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3462 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3463 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3464 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3465 // in Shogi, Hijack the unused Queen for Lance
\r
3466 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3467 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3468 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3470 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3475 if(squareSize <= 72 && squareSize >= 33) {
\r
3476 /* A & C are available in most sizes now */
\r
3477 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3478 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3479 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3480 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3481 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3482 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3483 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3484 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3485 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3486 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3487 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3488 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3489 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3490 } else { // Smirf-like
\r
3491 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3492 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3493 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3495 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3496 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3497 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3498 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3499 } else { // WinBoard standard
\r
3500 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3507 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3508 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3511 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3514 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3515 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3516 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3517 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3518 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3519 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3520 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3523 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3524 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3525 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3526 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3529 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3532 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3539 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3540 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3556 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3557 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3558 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3559 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3560 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3561 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3562 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3567 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3568 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3569 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3570 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3571 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3572 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3573 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3574 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3575 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3576 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3577 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3578 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3579 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3580 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3581 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3585 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3586 /* special Shogi support in this size */
\r
3587 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3588 for (piece = WhitePawn;
\r
3589 (int) piece < (int) BlackPawn;
\r
3590 piece = (ChessSquare) ((int) piece + 1)) {
\r
3591 if (pieceBitmap[i][piece] != NULL)
\r
3592 DeleteObject(pieceBitmap[i][piece]);
\r
3595 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3601 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3602 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3603 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3604 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3605 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3606 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3607 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3608 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3609 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3615 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3616 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3617 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3618 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3619 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3620 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3621 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3622 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3623 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3629 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3630 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3631 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3632 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3633 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3634 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3635 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3636 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3642 PieceBitmap(ChessSquare p, int kind)
\r
3644 if ((int) p >= (int) BlackPawn)
\r
3645 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3647 return pieceBitmap[kind][(int) p];
\r
3650 /***************************************************************/
\r
3652 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3653 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3655 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3656 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3660 SquareToPos(int row, int column, int * x, int * y)
\r
3663 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3664 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3666 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3667 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3672 DrawCoordsOnDC(HDC hdc)
\r
3674 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3675 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3676 char str[2] = { NULLCHAR, NULLCHAR };
\r
3677 int oldMode, oldAlign, x, y, start, i;
\r
3681 if (!appData.showCoords)
\r
3684 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3686 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3687 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3688 oldAlign = GetTextAlign(hdc);
\r
3689 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3691 y = boardRect.top + lineGap;
\r
3692 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3694 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3695 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3696 str[0] = files[start + i];
\r
3697 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3698 y += squareSize + lineGap;
\r
3701 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3703 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3704 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3705 str[0] = ranks[start + i];
\r
3706 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3707 x += squareSize + lineGap;
\r
3710 SelectObject(hdc, oldBrush);
\r
3711 SetBkMode(hdc, oldMode);
\r
3712 SetTextAlign(hdc, oldAlign);
\r
3713 SelectObject(hdc, oldFont);
\r
3717 DrawGridOnDC(HDC hdc)
\r
3721 if (lineGap != 0) {
\r
3722 oldPen = SelectObject(hdc, gridPen);
\r
3723 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3724 SelectObject(hdc, oldPen);
\r
3728 #define HIGHLIGHT_PEN 0
\r
3729 #define PREMOVE_PEN 1
\r
3732 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3735 HPEN oldPen, hPen;
\r
3736 if (lineGap == 0) return;
\r
3738 x1 = boardRect.left +
\r
3739 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3740 y1 = boardRect.top +
\r
3741 lineGap/2 + y * (squareSize + lineGap);
\r
3743 x1 = boardRect.left +
\r
3744 lineGap/2 + x * (squareSize + lineGap);
\r
3745 y1 = boardRect.top +
\r
3746 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3748 hPen = pen ? premovePen : highlightPen;
\r
3749 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3750 MoveToEx(hdc, x1, y1, NULL);
\r
3751 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3752 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3753 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3754 LineTo(hdc, x1, y1);
\r
3755 SelectObject(hdc, oldPen);
\r
3759 DrawHighlightsOnDC(HDC hdc)
\r
3762 for (i=0; i<2; i++) {
\r
3763 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3764 DrawHighlightOnDC(hdc, TRUE,
\r
3765 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3768 for (i=0; i<2; i++) {
\r
3769 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3770 premoveHighlightInfo.sq[i].y >= 0) {
\r
3771 DrawHighlightOnDC(hdc, TRUE,
\r
3772 premoveHighlightInfo.sq[i].x,
\r
3773 premoveHighlightInfo.sq[i].y,
\r
3779 /* Note: sqcolor is used only in monoMode */
\r
3780 /* Note that this code is largely duplicated in woptions.c,
\r
3781 function DrawSampleSquare, so that needs to be updated too */
\r
3783 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3785 HBITMAP oldBitmap;
\r
3789 if (appData.blindfold) return;
\r
3791 /* [AS] Use font-based pieces if needed */
\r
3792 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3793 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3794 CreatePiecesFromFont();
\r
3796 if( fontBitmapSquareSize == squareSize ) {
\r
3797 int index = TranslatePieceToFontPiece(piece);
\r
3799 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3803 squareSize, squareSize,
\r
3808 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3812 squareSize, squareSize,
\r
3821 if (appData.monoMode) {
\r
3822 SelectObject(tmphdc, PieceBitmap(piece,
\r
3823 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3824 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3825 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3827 tmpSize = squareSize;
\r
3829 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3830 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3831 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3832 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3833 x += (squareSize - minorSize)>>1;
\r
3834 y += squareSize - minorSize - 2;
\r
3835 tmpSize = minorSize;
\r
3837 if (color || appData.allWhite ) {
\r
3838 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3840 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3841 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3842 if(appData.upsideDown && color==flipView)
\r
3843 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3845 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3846 /* Use black for outline of white pieces */
\r
3847 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3848 if(appData.upsideDown && color==flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3853 /* Use square color for details of black pieces */
\r
3854 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3855 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3856 if(appData.upsideDown && !flipView)
\r
3857 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3859 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3861 SelectObject(hdc, oldBrush);
\r
3862 SelectObject(tmphdc, oldBitmap);
\r
3866 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3867 int GetBackTextureMode( int algo )
\r
3869 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3873 case BACK_TEXTURE_MODE_PLAIN:
\r
3874 result = 1; /* Always use identity map */
\r
3876 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3877 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3885 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3886 to handle redraws cleanly (as random numbers would always be different).
\r
3888 VOID RebuildTextureSquareInfo()
\r
3898 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3900 if( liteBackTexture != NULL ) {
\r
3901 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3902 lite_w = bi.bmWidth;
\r
3903 lite_h = bi.bmHeight;
\r
3907 if( darkBackTexture != NULL ) {
\r
3908 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3909 dark_w = bi.bmWidth;
\r
3910 dark_h = bi.bmHeight;
\r
3914 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3915 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3916 if( (col + row) & 1 ) {
\r
3918 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3926 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3927 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3928 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3929 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3936 /* [AS] Arrow highlighting support */
\r
3938 static int A_WIDTH = 5; /* Width of arrow body */
\r
3940 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3941 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3943 static double Sqr( double x )
\r
3948 static int Round( double x )
\r
3950 return (int) (x + 0.5);
\r
3953 /* Draw an arrow between two points using current settings */
\r
3954 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3957 double dx, dy, j, k, x, y;
\r
3959 if( d_x == s_x ) {
\r
3960 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3962 arrow[0].x = s_x + A_WIDTH;
\r
3965 arrow[1].x = s_x + A_WIDTH;
\r
3966 arrow[1].y = d_y - h;
\r
3968 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3969 arrow[2].y = d_y - h;
\r
3974 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3975 arrow[4].y = d_y - h;
\r
3977 arrow[5].x = s_x - A_WIDTH;
\r
3978 arrow[5].y = d_y - h;
\r
3980 arrow[6].x = s_x - A_WIDTH;
\r
3983 else if( d_y == s_y ) {
\r
3984 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3987 arrow[0].y = s_y + A_WIDTH;
\r
3989 arrow[1].x = d_x - w;
\r
3990 arrow[1].y = s_y + A_WIDTH;
\r
3992 arrow[2].x = d_x - w;
\r
3993 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3998 arrow[4].x = d_x - w;
\r
3999 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4001 arrow[5].x = d_x - w;
\r
4002 arrow[5].y = s_y - A_WIDTH;
\r
4005 arrow[6].y = s_y - A_WIDTH;
\r
4008 /* [AS] Needed a lot of paper for this! :-) */
\r
4009 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4010 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4012 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4014 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4019 arrow[0].x = Round(x - j);
\r
4020 arrow[0].y = Round(y + j*dx);
\r
4022 arrow[1].x = Round(x + j);
\r
4023 arrow[1].y = Round(y - j*dx);
\r
4026 x = (double) d_x - k;
\r
4027 y = (double) d_y - k*dy;
\r
4030 x = (double) d_x + k;
\r
4031 y = (double) d_y + k*dy;
\r
4034 arrow[2].x = Round(x + j);
\r
4035 arrow[2].y = Round(y - j*dx);
\r
4037 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4038 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4043 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4044 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4046 arrow[6].x = Round(x - j);
\r
4047 arrow[6].y = Round(y + j*dx);
\r
4050 Polygon( hdc, arrow, 7 );
\r
4053 /* [AS] Draw an arrow between two squares */
\r
4054 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4056 int s_x, s_y, d_x, d_y;
\r
4063 if( s_col == d_col && s_row == d_row ) {
\r
4067 /* Get source and destination points */
\r
4068 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4069 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4072 d_y += squareSize / 4;
\r
4074 else if( d_y < s_y ) {
\r
4075 d_y += 3 * squareSize / 4;
\r
4078 d_y += squareSize / 2;
\r
4082 d_x += squareSize / 4;
\r
4084 else if( d_x < s_x ) {
\r
4085 d_x += 3 * squareSize / 4;
\r
4088 d_x += squareSize / 2;
\r
4091 s_x += squareSize / 2;
\r
4092 s_y += squareSize / 2;
\r
4094 /* Adjust width */
\r
4095 A_WIDTH = squareSize / 14;
\r
4098 stLB.lbStyle = BS_SOLID;
\r
4099 stLB.lbColor = appData.highlightArrowColor;
\r
4102 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4103 holdpen = SelectObject( hdc, hpen );
\r
4104 hbrush = CreateBrushIndirect( &stLB );
\r
4105 holdbrush = SelectObject( hdc, hbrush );
\r
4107 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4109 SelectObject( hdc, holdpen );
\r
4110 SelectObject( hdc, holdbrush );
\r
4111 DeleteObject( hpen );
\r
4112 DeleteObject( hbrush );
\r
4115 BOOL HasHighlightInfo()
\r
4117 BOOL result = FALSE;
\r
4119 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4120 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4128 BOOL IsDrawArrowEnabled()
\r
4130 BOOL result = FALSE;
\r
4132 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4139 VOID DrawArrowHighlight( HDC hdc )
\r
4141 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4142 DrawArrowBetweenSquares( hdc,
\r
4143 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4144 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4148 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4150 HRGN result = NULL;
\r
4152 if( HasHighlightInfo() ) {
\r
4153 int x1, y1, x2, y2;
\r
4154 int sx, sy, dx, dy;
\r
4156 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4157 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4159 sx = MIN( x1, x2 );
\r
4160 sy = MIN( y1, y2 );
\r
4161 dx = MAX( x1, x2 ) + squareSize;
\r
4162 dy = MAX( y1, y2 ) + squareSize;
\r
4164 result = CreateRectRgn( sx, sy, dx, dy );
\r
4171 Warning: this function modifies the behavior of several other functions.
\r
4173 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4174 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4175 repaint is scattered all over the place, which is not good for features such as
\r
4176 "arrow highlighting" that require a full repaint of the board.
\r
4178 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4179 user interaction, when speed is not so important) but especially to avoid errors
\r
4180 in the displayed graphics.
\r
4182 In such patched places, I always try refer to this function so there is a single
\r
4183 place to maintain knowledge.
\r
4185 To restore the original behavior, just return FALSE unconditionally.
\r
4187 BOOL IsFullRepaintPreferrable()
\r
4189 BOOL result = FALSE;
\r
4191 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4192 /* Arrow may appear on the board */
\r
4200 This function is called by DrawPosition to know whether a full repaint must
\r
4203 Only DrawPosition may directly call this function, which makes use of
\r
4204 some state information. Other function should call DrawPosition specifying
\r
4205 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4207 BOOL DrawPositionNeedsFullRepaint()
\r
4209 BOOL result = FALSE;
\r
4212 Probably a slightly better policy would be to trigger a full repaint
\r
4213 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4214 but animation is fast enough that it's difficult to notice.
\r
4216 if( animInfo.piece == EmptySquare ) {
\r
4217 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4226 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4228 int row, column, x, y, square_color, piece_color;
\r
4229 ChessSquare piece;
\r
4231 HDC texture_hdc = NULL;
\r
4233 /* [AS] Initialize background textures if needed */
\r
4234 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4235 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4236 if( backTextureSquareSize != squareSize
\r
4237 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4238 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4239 backTextureSquareSize = squareSize;
\r
4240 RebuildTextureSquareInfo();
\r
4243 texture_hdc = CreateCompatibleDC( hdc );
\r
4246 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4247 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4249 SquareToPos(row, column, &x, &y);
\r
4251 piece = board[row][column];
\r
4253 square_color = ((column + row) % 2) == 1;
\r
4254 if( gameInfo.variant == VariantXiangqi ) {
\r
4255 square_color = !InPalace(row, column);
\r
4256 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4257 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4259 piece_color = (int) piece < (int) BlackPawn;
\r
4262 /* [HGM] holdings file: light square or black */
\r
4263 if(column == BOARD_LEFT-2) {
\r
4264 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4271 if(column == BOARD_RGHT + 1 ) {
\r
4272 if( row < gameInfo.holdingsSize )
\r
4275 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4279 if(column == BOARD_LEFT-1 ) /* left align */
\r
4280 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4281 else if( column == BOARD_RGHT) /* right align */
\r
4282 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4284 if (appData.monoMode) {
\r
4285 if (piece == EmptySquare) {
\r
4286 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4287 square_color ? WHITENESS : BLACKNESS);
\r
4289 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4292 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4293 /* [AS] Draw the square using a texture bitmap */
\r
4294 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4295 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4296 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4299 squareSize, squareSize,
\r
4302 backTextureSquareInfo[r][c].mode,
\r
4303 backTextureSquareInfo[r][c].x,
\r
4304 backTextureSquareInfo[r][c].y );
\r
4306 SelectObject( texture_hdc, hbm );
\r
4308 if (piece != EmptySquare) {
\r
4309 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4313 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4315 oldBrush = SelectObject(hdc, brush );
\r
4316 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4317 SelectObject(hdc, oldBrush);
\r
4318 if (piece != EmptySquare)
\r
4319 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4324 if( texture_hdc != NULL ) {
\r
4325 DeleteDC( texture_hdc );
\r
4329 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4330 void fputDW(FILE *f, int x)
\r
4332 fputc(x & 255, f);
\r
4333 fputc(x>>8 & 255, f);
\r
4334 fputc(x>>16 & 255, f);
\r
4335 fputc(x>>24 & 255, f);
\r
4338 #define MAX_CLIPS 200 /* more than enough */
\r
4341 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4343 // HBITMAP bufferBitmap;
\r
4348 int w = 100, h = 50;
\r
4350 if(logo == NULL) return;
\r
4351 // GetClientRect(hwndMain, &Rect);
\r
4352 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4353 // Rect.bottom-Rect.top+1);
\r
4354 tmphdc = CreateCompatibleDC(hdc);
\r
4355 hbm = SelectObject(tmphdc, logo);
\r
4356 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4360 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4361 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4362 SelectObject(tmphdc, hbm);
\r
4367 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4369 static Board lastReq, lastDrawn;
\r
4370 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4371 static int lastDrawnFlipView = 0;
\r
4372 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4373 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4376 HBITMAP bufferBitmap;
\r
4377 HBITMAP oldBitmap;
\r
4379 HRGN clips[MAX_CLIPS];
\r
4380 ChessSquare dragged_piece = EmptySquare;
\r
4382 /* I'm undecided on this - this function figures out whether a full
\r
4383 * repaint is necessary on its own, so there's no real reason to have the
\r
4384 * caller tell it that. I think this can safely be set to FALSE - but
\r
4385 * if we trust the callers not to request full repaints unnessesarily, then
\r
4386 * we could skip some clipping work. In other words, only request a full
\r
4387 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4388 * gamestart and similar) --Hawk
\r
4390 Boolean fullrepaint = repaint;
\r
4392 if( DrawPositionNeedsFullRepaint() ) {
\r
4393 fullrepaint = TRUE;
\r
4396 if (board == NULL) {
\r
4397 if (!lastReqValid) {
\r
4402 CopyBoard(lastReq, board);
\r
4406 if (doingSizing) {
\r
4410 if (IsIconic(hwndMain)) {
\r
4414 if (hdc == NULL) {
\r
4415 hdc = GetDC(hwndMain);
\r
4416 if (!appData.monoMode) {
\r
4417 SelectPalette(hdc, hPal, FALSE);
\r
4418 RealizePalette(hdc);
\r
4422 releaseDC = FALSE;
\r
4425 /* Create some work-DCs */
\r
4426 hdcmem = CreateCompatibleDC(hdc);
\r
4427 tmphdc = CreateCompatibleDC(hdc);
\r
4429 /* If dragging is in progress, we temporarely remove the piece */
\r
4430 /* [HGM] or temporarily decrease count if stacked */
\r
4431 /* !! Moved to before board compare !! */
\r
4432 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4433 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4434 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4435 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4436 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4438 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4439 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4440 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4442 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4445 /* Figure out which squares need updating by comparing the
\r
4446 * newest board with the last drawn board and checking if
\r
4447 * flipping has changed.
\r
4449 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4450 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4451 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4452 if (lastDrawn[row][column] != board[row][column]) {
\r
4453 SquareToPos(row, column, &x, &y);
\r
4454 clips[num_clips++] =
\r
4455 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4459 for (i=0; i<2; i++) {
\r
4460 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4461 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4462 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4463 lastDrawnHighlight.sq[i].y >= 0) {
\r
4464 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4465 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4466 clips[num_clips++] =
\r
4467 CreateRectRgn(x - lineGap, y - lineGap,
\r
4468 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4471 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4472 clips[num_clips++] =
\r
4473 CreateRectRgn(x - lineGap, y - lineGap,
\r
4474 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4478 for (i=0; i<2; i++) {
\r
4479 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4480 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4481 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4482 lastDrawnPremove.sq[i].y >= 0) {
\r
4483 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4484 lastDrawnPremove.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4489 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4490 premoveHighlightInfo.sq[i].y >= 0) {
\r
4491 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4492 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4493 clips[num_clips++] =
\r
4494 CreateRectRgn(x - lineGap, y - lineGap,
\r
4495 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4500 fullrepaint = TRUE;
\r
4503 /* Create a buffer bitmap - this is the actual bitmap
\r
4504 * being written to. When all the work is done, we can
\r
4505 * copy it to the real DC (the screen). This avoids
\r
4506 * the problems with flickering.
\r
4508 GetClientRect(hwndMain, &Rect);
\r
4509 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4510 Rect.bottom-Rect.top+1);
\r
4511 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4512 if (!appData.monoMode) {
\r
4513 SelectPalette(hdcmem, hPal, FALSE);
\r
4516 /* Create clips for dragging */
\r
4517 if (!fullrepaint) {
\r
4518 if (dragInfo.from.x >= 0) {
\r
4519 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4520 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4522 if (dragInfo.start.x >= 0) {
\r
4523 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4524 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4526 if (dragInfo.pos.x >= 0) {
\r
4527 x = dragInfo.pos.x - squareSize / 2;
\r
4528 y = dragInfo.pos.y - squareSize / 2;
\r
4529 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4531 if (dragInfo.lastpos.x >= 0) {
\r
4532 x = dragInfo.lastpos.x - squareSize / 2;
\r
4533 y = dragInfo.lastpos.y - squareSize / 2;
\r
4534 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4538 /* Are we animating a move?
\r
4540 * - remove the piece from the board (temporarely)
\r
4541 * - calculate the clipping region
\r
4543 if (!fullrepaint) {
\r
4544 if (animInfo.piece != EmptySquare) {
\r
4545 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4546 x = boardRect.left + animInfo.lastpos.x;
\r
4547 y = boardRect.top + animInfo.lastpos.y;
\r
4548 x2 = boardRect.left + animInfo.pos.x;
\r
4549 y2 = boardRect.top + animInfo.pos.y;
\r
4550 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4551 /* Slight kludge. The real problem is that after AnimateMove is
\r
4552 done, the position on the screen does not match lastDrawn.
\r
4553 This currently causes trouble only on e.p. captures in
\r
4554 atomic, where the piece moves to an empty square and then
\r
4555 explodes. The old and new positions both had an empty square
\r
4556 at the destination, but animation has drawn a piece there and
\r
4557 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4558 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4562 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4563 if (num_clips == 0)
\r
4564 fullrepaint = TRUE;
\r
4566 /* Set clipping on the memory DC */
\r
4567 if (!fullrepaint) {
\r
4568 SelectClipRgn(hdcmem, clips[0]);
\r
4569 for (x = 1; x < num_clips; x++) {
\r
4570 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4571 abort(); // this should never ever happen!
\r
4575 /* Do all the drawing to the memory DC */
\r
4576 if(explodeInfo.radius) { // [HGM] atomic
\r
4578 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4579 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4580 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4581 x += squareSize/2;
\r
4582 y += squareSize/2;
\r
4583 if(!fullrepaint) {
\r
4584 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4585 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4587 DrawGridOnDC(hdcmem);
\r
4588 DrawHighlightsOnDC(hdcmem);
\r
4589 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4590 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4591 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4592 SelectObject(hdcmem, oldBrush);
\r
4594 DrawGridOnDC(hdcmem);
\r
4595 DrawHighlightsOnDC(hdcmem);
\r
4596 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4599 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4600 if(appData.autoLogo) {
\r
4602 switch(gameMode) { // pick logos based on game mode
\r
4603 case IcsObserving:
\r
4604 whiteLogo = second.programLogo; // ICS logo
\r
4605 blackLogo = second.programLogo;
\r
4608 case IcsPlayingWhite:
\r
4609 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4610 blackLogo = second.programLogo; // ICS logo
\r
4612 case IcsPlayingBlack:
\r
4613 whiteLogo = second.programLogo; // ICS logo
\r
4614 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4616 case TwoMachinesPlay:
\r
4617 if(first.twoMachinesColor[0] == 'b') {
\r
4618 whiteLogo = second.programLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 case MachinePlaysWhite:
\r
4623 blackLogo = userLogo;
\r
4625 case MachinePlaysBlack:
\r
4626 whiteLogo = userLogo;
\r
4627 blackLogo = first.programLogo;
\r
4630 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4631 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4634 if( appData.highlightMoveWithArrow ) {
\r
4635 DrawArrowHighlight(hdcmem);
\r
4638 DrawCoordsOnDC(hdcmem);
\r
4640 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4641 /* to make sure lastDrawn contains what is actually drawn */
\r
4643 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4644 if (dragged_piece != EmptySquare) {
\r
4645 /* [HGM] or restack */
\r
4646 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4647 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4649 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4650 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4651 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4652 x = dragInfo.pos.x - squareSize / 2;
\r
4653 y = dragInfo.pos.y - squareSize / 2;
\r
4654 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4655 ((int) dragged_piece < (int) BlackPawn),
\r
4656 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4659 /* Put the animated piece back into place and draw it */
\r
4660 if (animInfo.piece != EmptySquare) {
\r
4661 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4662 x = boardRect.left + animInfo.pos.x;
\r
4663 y = boardRect.top + animInfo.pos.y;
\r
4664 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4665 ((int) animInfo.piece < (int) BlackPawn),
\r
4666 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4669 /* Release the bufferBitmap by selecting in the old bitmap
\r
4670 * and delete the memory DC
\r
4672 SelectObject(hdcmem, oldBitmap);
\r
4675 /* Set clipping on the target DC */
\r
4676 if (!fullrepaint) {
\r
4677 SelectClipRgn(hdc, clips[0]);
\r
4678 for (x = 1; x < num_clips; x++) {
\r
4679 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4680 abort(); // this should never ever happen!
\r
4684 /* Copy the new bitmap onto the screen in one go.
\r
4685 * This way we avoid any flickering
\r
4687 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4688 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4689 boardRect.right - boardRect.left,
\r
4690 boardRect.bottom - boardRect.top,
\r
4691 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4692 if(saveDiagFlag) {
\r
4693 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4694 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4696 GetObject(bufferBitmap, sizeof(b), &b);
\r
4697 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4698 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4699 bih.biWidth = b.bmWidth;
\r
4700 bih.biHeight = b.bmHeight;
\r
4702 bih.biBitCount = b.bmBitsPixel;
\r
4703 bih.biCompression = 0;
\r
4704 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4705 bih.biXPelsPerMeter = 0;
\r
4706 bih.biYPelsPerMeter = 0;
\r
4707 bih.biClrUsed = 0;
\r
4708 bih.biClrImportant = 0;
\r
4709 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4710 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4711 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4712 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4714 wb = b.bmWidthBytes;
\r
4716 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4717 int k = ((int*) pData)[i];
\r
4718 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4719 if(j >= 16) break;
\r
4721 if(j >= nrColors) nrColors = j+1;
\r
4723 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4725 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4726 for(w=0; w<(wb>>2); w+=2) {
\r
4727 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4728 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4729 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4730 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4731 pData[p++] = m | j<<4;
\r
4733 while(p&3) pData[p++] = 0;
\r
4736 wb = ((wb+31)>>5)<<2;
\r
4738 // write BITMAPFILEHEADER
\r
4739 fprintf(diagFile, "BM");
\r
4740 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4743 // write BITMAPINFOHEADER
\r
4744 fputDW(diagFile, 40);
\r
4745 fputDW(diagFile, b.bmWidth);
\r
4746 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4747 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4748 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4749 fputDW(diagFile, 0);
\r
4750 fputDW(diagFile, 0);
\r
4751 fputDW(diagFile, 0);
\r
4752 fputDW(diagFile, 0);
\r
4753 fputDW(diagFile, 0);
\r
4754 fputDW(diagFile, 0);
\r
4755 // write color table
\r
4757 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4758 // write bitmap data
\r
4759 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4760 fputc(pData[i], diagFile);
\r
4764 SelectObject(tmphdc, oldBitmap);
\r
4766 /* Massive cleanup */
\r
4767 for (x = 0; x < num_clips; x++)
\r
4768 DeleteObject(clips[x]);
\r
4771 DeleteObject(bufferBitmap);
\r
4774 ReleaseDC(hwndMain, hdc);
\r
4776 if (lastDrawnFlipView != flipView) {
\r
4778 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4780 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4783 /* CopyBoard(lastDrawn, board);*/
\r
4784 lastDrawnHighlight = highlightInfo;
\r
4785 lastDrawnPremove = premoveHighlightInfo;
\r
4786 lastDrawnFlipView = flipView;
\r
4787 lastDrawnValid = 1;
\r
4790 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4795 saveDiagFlag = 1; diagFile = f;
\r
4796 HDCDrawPosition(NULL, TRUE, NULL);
\r
4800 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4807 /*---------------------------------------------------------------------------*\
\r
4808 | CLIENT PAINT PROCEDURE
\r
4809 | This is the main event-handler for the WM_PAINT message.
\r
4811 \*---------------------------------------------------------------------------*/
\r
4813 PaintProc(HWND hwnd)
\r
4819 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4820 if (IsIconic(hwnd)) {
\r
4821 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4823 if (!appData.monoMode) {
\r
4824 SelectPalette(hdc, hPal, FALSE);
\r
4825 RealizePalette(hdc);
\r
4827 HDCDrawPosition(hdc, 1, NULL);
\r
4829 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4830 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4831 ETO_CLIPPED|ETO_OPAQUE,
\r
4832 &messageRect, messageText, strlen(messageText), NULL);
\r
4833 SelectObject(hdc, oldFont);
\r
4834 DisplayBothClocks();
\r
4836 EndPaint(hwnd,&ps);
\r
4844 * If the user selects on a border boundary, return -1; if off the board,
\r
4845 * return -2. Otherwise map the event coordinate to the square.
\r
4846 * The offset boardRect.left or boardRect.top must already have been
\r
4847 * subtracted from x.
\r
4849 int EventToSquare(x, limit)
\r
4857 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4859 x /= (squareSize + lineGap);
\r
4871 DropEnable dropEnables[] = {
\r
4872 { 'P', DP_Pawn, "Pawn" },
\r
4873 { 'N', DP_Knight, "Knight" },
\r
4874 { 'B', DP_Bishop, "Bishop" },
\r
4875 { 'R', DP_Rook, "Rook" },
\r
4876 { 'Q', DP_Queen, "Queen" },
\r
4880 SetupDropMenu(HMENU hmenu)
\r
4882 int i, count, enable;
\r
4884 extern char white_holding[], black_holding[];
\r
4885 char item[MSG_SIZ];
\r
4887 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4888 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4889 dropEnables[i].piece);
\r
4891 while (p && *p++ == dropEnables[i].piece) count++;
\r
4892 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4893 enable = count > 0 || !appData.testLegality
\r
4894 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4895 && !appData.icsActive);
\r
4896 ModifyMenu(hmenu, dropEnables[i].command,
\r
4897 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4898 dropEnables[i].command, item);
\r
4902 void DragPieceBegin(int x, int y)
\r
4904 dragInfo.lastpos.x = boardRect.left + x;
\r
4905 dragInfo.lastpos.y = boardRect.top + y;
\r
4906 dragInfo.from.x = fromX;
\r
4907 dragInfo.from.y = fromY;
\r
4908 dragInfo.start = dragInfo.from;
\r
4909 SetCapture(hwndMain);
\r
4912 void DragPieceEnd(int x, int y)
\r
4915 dragInfo.start.x = dragInfo.start.y = -1;
\r
4916 dragInfo.from = dragInfo.start;
\r
4917 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4920 /* Event handler for mouse messages */
\r
4922 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4926 static int recursive = 0;
\r
4928 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4931 if (message == WM_MBUTTONUP) {
\r
4932 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4933 to the middle button: we simulate pressing the left button too!
\r
4935 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4936 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4942 pt.x = LOWORD(lParam);
\r
4943 pt.y = HIWORD(lParam);
\r
4944 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4945 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4946 if (!flipView && y >= 0) {
\r
4947 y = BOARD_HEIGHT - 1 - y;
\r
4949 if (flipView && x >= 0) {
\r
4950 x = BOARD_WIDTH - 1 - x;
\r
4953 switch (message) {
\r
4954 case WM_LBUTTONDOWN:
\r
4955 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4956 if (gameMode == EditPosition) {
\r
4957 SetWhiteToPlayEvent();
\r
4958 } else if (gameMode == IcsPlayingBlack ||
\r
4959 gameMode == MachinePlaysWhite) {
\r
4961 } else if (gameMode == EditGame) {
\r
4962 AdjustClock(flipClock, -1);
\r
4964 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4965 if (gameMode == EditPosition) {
\r
4966 SetBlackToPlayEvent();
\r
4967 } else if (gameMode == IcsPlayingWhite ||
\r
4968 gameMode == MachinePlaysBlack) {
\r
4970 } else if (gameMode == EditGame) {
\r
4971 AdjustClock(!flipClock, -1);
\r
4974 dragInfo.start.x = dragInfo.start.y = -1;
\r
4975 dragInfo.from = dragInfo.start;
\r
4976 if(fromX == -1 && frozen) { // not sure where this is for
\r
4977 fromX = fromY = -1;
\r
4978 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4981 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4982 DrawPosition(TRUE, NULL);
\r
4985 case WM_LBUTTONUP:
\r
4986 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4987 DrawPosition(TRUE, NULL);
\r
4990 case WM_MOUSEMOVE:
\r
4991 if ((appData.animateDragging || appData.highlightDragging)
\r
4992 && (wParam & MK_LBUTTON)
\r
4993 && dragInfo.from.x >= 0)
\r
4995 BOOL full_repaint = FALSE;
\r
4997 if (appData.animateDragging) {
\r
4998 dragInfo.pos = pt;
\r
5000 if (appData.highlightDragging) {
\r
5001 SetHighlights(fromX, fromY, x, y);
\r
5002 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5003 full_repaint = TRUE;
\r
5007 DrawPosition( full_repaint, NULL);
\r
5009 dragInfo.lastpos = dragInfo.pos;
\r
5013 case WM_MOUSEWHEEL: // [DM]
\r
5014 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5015 /* Mouse Wheel is being rolled forward
\r
5016 * Play moves forward
\r
5018 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5019 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5020 /* Mouse Wheel is being rolled backward
\r
5021 * Play moves backward
\r
5023 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5024 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5028 case WM_MBUTTONDOWN:
\r
5029 case WM_RBUTTONDOWN:
\r
5032 fromX = fromY = -1;
\r
5033 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5034 dragInfo.start.x = dragInfo.start.y = -1;
\r
5035 dragInfo.from = dragInfo.start;
\r
5036 dragInfo.lastpos = dragInfo.pos;
\r
5037 if (appData.highlightDragging) {
\r
5038 ClearHighlights();
\r
5041 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5042 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5043 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5044 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5045 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5048 DrawPosition(TRUE, NULL);
\r
5050 switch (gameMode) {
\r
5051 case EditPosition:
\r
5052 case IcsExamining:
\r
5053 if (x < 0 || y < 0) break;
\r
5056 if (message == WM_MBUTTONDOWN) {
\r
5057 buttonCount = 3; /* even if system didn't think so */
\r
5058 if (wParam & MK_SHIFT)
\r
5059 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5061 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5062 } else { /* message == WM_RBUTTONDOWN */
\r
5063 /* Just have one menu, on the right button. Windows users don't
\r
5064 think to try the middle one, and sometimes other software steals
\r
5065 it, or it doesn't really exist. */
\r
5066 if(gameInfo.variant != VariantShogi)
\r
5067 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5069 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5072 case IcsPlayingWhite:
\r
5073 case IcsPlayingBlack:
\r
5075 case MachinePlaysWhite:
\r
5076 case MachinePlaysBlack:
\r
5077 if (appData.testLegality &&
\r
5078 gameInfo.variant != VariantBughouse &&
\r
5079 gameInfo.variant != VariantCrazyhouse) break;
\r
5080 if (x < 0 || y < 0) break;
\r
5083 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5084 SetupDropMenu(hmenu);
\r
5085 MenuPopup(hwnd, pt, hmenu, -1);
\r
5096 /* Preprocess messages for buttons in main window */
\r
5098 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5100 int id = GetWindowLong(hwnd, GWL_ID);
\r
5103 for (i=0; i<N_BUTTONS; i++) {
\r
5104 if (buttonDesc[i].id == id) break;
\r
5106 if (i == N_BUTTONS) return 0;
\r
5107 switch (message) {
\r
5112 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5113 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5120 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5123 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5124 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5125 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5126 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5128 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5130 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5131 PopUpMoveDialog((char)wParam);
\r
5137 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5140 /* Process messages for Promotion dialog box */
\r
5142 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5146 switch (message) {
\r
5147 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5148 /* Center the dialog over the application window */
\r
5149 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5150 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5151 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5152 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5153 SW_SHOW : SW_HIDE);
\r
5154 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5155 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5156 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5157 PieceToChar(WhiteAngel) != '~') ||
\r
5158 (PieceToChar(BlackAngel) >= 'A' &&
\r
5159 PieceToChar(BlackAngel) != '~') ) ?
\r
5160 SW_SHOW : SW_HIDE);
\r
5161 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5162 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5163 PieceToChar(WhiteMarshall) != '~') ||
\r
5164 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5165 PieceToChar(BlackMarshall) != '~') ) ?
\r
5166 SW_SHOW : SW_HIDE);
\r
5167 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5168 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5169 gameInfo.variant != VariantShogi ?
\r
5170 SW_SHOW : SW_HIDE);
\r
5171 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5172 gameInfo.variant != VariantShogi ?
\r
5173 SW_SHOW : SW_HIDE);
\r
5174 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5175 gameInfo.variant == VariantShogi ?
\r
5176 SW_SHOW : SW_HIDE);
\r
5177 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5178 gameInfo.variant == VariantShogi ?
\r
5179 SW_SHOW : SW_HIDE);
\r
5180 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5181 gameInfo.variant == VariantSuper ?
\r
5182 SW_SHOW : SW_HIDE);
\r
5185 case WM_COMMAND: /* message: received a command */
\r
5186 switch (LOWORD(wParam)) {
\r
5188 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5189 ClearHighlights();
\r
5190 DrawPosition(FALSE, NULL);
\r
5193 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5196 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5199 promoChar = PieceToChar(BlackRook);
\r
5202 promoChar = PieceToChar(BlackBishop);
\r
5204 case PB_Chancellor:
\r
5205 promoChar = PieceToChar(BlackMarshall);
\r
5207 case PB_Archbishop:
\r
5208 promoChar = PieceToChar(BlackAngel);
\r
5211 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5216 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5217 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5218 only show the popup when we are already sure the move is valid or
\r
5219 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5220 will figure out it is a promotion from the promoChar. */
\r
5221 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5222 fromX = fromY = -1;
\r
5223 if (!appData.highlightLastMove) {
\r
5224 ClearHighlights();
\r
5225 DrawPosition(FALSE, NULL);
\r
5232 /* Pop up promotion dialog */
\r
5234 PromotionPopup(HWND hwnd)
\r
5238 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5239 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5240 hwnd, (DLGPROC)lpProc);
\r
5241 FreeProcInstance(lpProc);
\r
5247 DrawPosition(TRUE, NULL);
\r
5248 PromotionPopup(hwndMain);
\r
5251 /* Toggle ShowThinking */
\r
5253 ToggleShowThinking()
\r
5255 appData.showThinking = !appData.showThinking;
\r
5256 ShowThinkingEvent();
\r
5260 LoadGameDialog(HWND hwnd, char* title)
\r
5264 char fileTitle[MSG_SIZ];
\r
5265 f = OpenFileDialog(hwnd, "rb", "",
\r
5266 appData.oldSaveStyle ? "gam" : "pgn",
\r
5268 title, &number, fileTitle, NULL);
\r
5270 cmailMsgLoaded = FALSE;
\r
5271 if (number == 0) {
\r
5272 int error = GameListBuild(f);
\r
5274 DisplayError("Cannot build game list", error);
\r
5275 } else if (!ListEmpty(&gameList) &&
\r
5276 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5277 GameListPopUp(f, fileTitle);
\r
5280 GameListDestroy();
\r
5283 LoadGame(f, number, fileTitle, FALSE);
\r
5287 int get_term_width()
\r
5292 HFONT hfont, hold_font;
\r
5297 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5301 // get the text metrics
\r
5302 hdc = GetDC(hText);
\r
5303 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5304 if (consoleCF.dwEffects & CFE_BOLD)
\r
5305 lf.lfWeight = FW_BOLD;
\r
5306 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5307 lf.lfItalic = TRUE;
\r
5308 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5309 lf.lfStrikeOut = TRUE;
\r
5310 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5311 lf.lfUnderline = TRUE;
\r
5312 hfont = CreateFontIndirect(&lf);
\r
5313 hold_font = SelectObject(hdc, hfont);
\r
5314 GetTextMetrics(hdc, &tm);
\r
5315 SelectObject(hdc, hold_font);
\r
5316 DeleteObject(hfont);
\r
5317 ReleaseDC(hText, hdc);
\r
5319 // get the rectangle
\r
5320 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5322 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5325 void UpdateICSWidth(HWND hText)
\r
5327 LONG old_width, new_width;
\r
5329 new_width = get_term_width(hText, FALSE);
\r
5330 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5331 if (new_width != old_width)
\r
5333 ics_update_width(new_width);
\r
5334 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5339 ChangedConsoleFont()
\r
5342 CHARRANGE tmpsel, sel;
\r
5343 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5344 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5345 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5348 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5349 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5350 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5351 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5352 * size. This was undocumented in the version of MSVC++ that I had
\r
5353 * when I wrote the code, but is apparently documented now.
\r
5355 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5356 cfmt.bCharSet = f->lf.lfCharSet;
\r
5357 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5358 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5359 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5360 /* Why are the following seemingly needed too? */
\r
5361 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5362 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5363 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5365 tmpsel.cpMax = -1; /*999999?*/
\r
5366 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5367 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5368 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5369 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5371 paraf.cbSize = sizeof(paraf);
\r
5372 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5373 paraf.dxStartIndent = 0;
\r
5374 paraf.dxOffset = WRAP_INDENT;
\r
5375 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5377 UpdateICSWidth(hText);
\r
5380 /*---------------------------------------------------------------------------*\
\r
5382 * Window Proc for main window
\r
5384 \*---------------------------------------------------------------------------*/
\r
5386 /* Process messages for main window, etc. */
\r
5388 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5391 int wmId, wmEvent;
\r
5395 char fileTitle[MSG_SIZ];
\r
5396 char buf[MSG_SIZ];
\r
5397 static SnapData sd;
\r
5399 switch (message) {
\r
5401 case WM_PAINT: /* message: repaint portion of window */
\r
5405 case WM_ERASEBKGND:
\r
5406 if (IsIconic(hwnd)) {
\r
5407 /* Cheat; change the message */
\r
5408 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5410 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5414 case WM_LBUTTONDOWN:
\r
5415 case WM_MBUTTONDOWN:
\r
5416 case WM_RBUTTONDOWN:
\r
5417 case WM_LBUTTONUP:
\r
5418 case WM_MBUTTONUP:
\r
5419 case WM_RBUTTONUP:
\r
5420 case WM_MOUSEMOVE:
\r
5421 case WM_MOUSEWHEEL:
\r
5422 MouseEvent(hwnd, message, wParam, lParam);
\r
5425 JAWS_KB_NAVIGATION
\r
5429 JAWS_ALT_INTERCEPT
\r
5431 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5432 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5433 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5434 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5436 SendMessage(h, message, wParam, lParam);
\r
5437 } else if(lParam != KF_REPEAT) {
\r
5438 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5439 PopUpMoveDialog((char)wParam);
\r
5440 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5441 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5446 case WM_PALETTECHANGED:
\r
5447 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5449 HDC hdc = GetDC(hwndMain);
\r
5450 SelectPalette(hdc, hPal, TRUE);
\r
5451 nnew = RealizePalette(hdc);
\r
5453 paletteChanged = TRUE;
\r
5454 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5456 ReleaseDC(hwnd, hdc);
\r
5460 case WM_QUERYNEWPALETTE:
\r
5461 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5463 HDC hdc = GetDC(hwndMain);
\r
5464 paletteChanged = FALSE;
\r
5465 SelectPalette(hdc, hPal, FALSE);
\r
5466 nnew = RealizePalette(hdc);
\r
5468 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5470 ReleaseDC(hwnd, hdc);
\r
5475 case WM_COMMAND: /* message: command from application menu */
\r
5476 wmId = LOWORD(wParam);
\r
5477 wmEvent = HIWORD(wParam);
\r
5482 SAY("new game enter a move to play against the computer with white");
\r
5485 case IDM_NewGameFRC:
\r
5486 if( NewGameFRC() == 0 ) {
\r
5491 case IDM_NewVariant:
\r
5492 NewVariantPopup(hwnd);
\r
5495 case IDM_LoadGame:
\r
5496 LoadGameDialog(hwnd, "Load Game from File");
\r
5499 case IDM_LoadNextGame:
\r
5503 case IDM_LoadPrevGame:
\r
5507 case IDM_ReloadGame:
\r
5511 case IDM_LoadPosition:
\r
5512 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5513 Reset(FALSE, TRUE);
\r
5516 f = OpenFileDialog(hwnd, "rb", "",
\r
5517 appData.oldSaveStyle ? "pos" : "fen",
\r
5519 "Load Position from File", &number, fileTitle, NULL);
\r
5521 LoadPosition(f, number, fileTitle);
\r
5525 case IDM_LoadNextPosition:
\r
5526 ReloadPosition(1);
\r
5529 case IDM_LoadPrevPosition:
\r
5530 ReloadPosition(-1);
\r
5533 case IDM_ReloadPosition:
\r
5534 ReloadPosition(0);
\r
5537 case IDM_SaveGame:
\r
5538 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5539 f = OpenFileDialog(hwnd, "a", defName,
\r
5540 appData.oldSaveStyle ? "gam" : "pgn",
\r
5542 "Save Game to File", NULL, fileTitle, NULL);
\r
5544 SaveGame(f, 0, "");
\r
5548 case IDM_SavePosition:
\r
5549 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5550 f = OpenFileDialog(hwnd, "a", defName,
\r
5551 appData.oldSaveStyle ? "pos" : "fen",
\r
5553 "Save Position to File", NULL, fileTitle, NULL);
\r
5555 SavePosition(f, 0, "");
\r
5559 case IDM_SaveDiagram:
\r
5560 defName = "diagram";
\r
5561 f = OpenFileDialog(hwnd, "wb", defName,
\r
5564 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5570 case IDM_CopyGame:
\r
5571 CopyGameToClipboard();
\r
5574 case IDM_PasteGame:
\r
5575 PasteGameFromClipboard();
\r
5578 case IDM_CopyGameListToClipboard:
\r
5579 CopyGameListToClipboard();
\r
5582 /* [AS] Autodetect FEN or PGN data */
\r
5583 case IDM_PasteAny:
\r
5584 PasteGameOrFENFromClipboard();
\r
5587 /* [AS] Move history */
\r
5588 case IDM_ShowMoveHistory:
\r
5589 if( MoveHistoryIsUp() ) {
\r
5590 MoveHistoryPopDown();
\r
5593 MoveHistoryPopUp();
\r
5597 /* [AS] Eval graph */
\r
5598 case IDM_ShowEvalGraph:
\r
5599 if( EvalGraphIsUp() ) {
\r
5600 EvalGraphPopDown();
\r
5604 SetFocus(hwndMain);
\r
5608 /* [AS] Engine output */
\r
5609 case IDM_ShowEngineOutput:
\r
5610 if( EngineOutputIsUp() ) {
\r
5611 EngineOutputPopDown();
\r
5614 EngineOutputPopUp();
\r
5618 /* [AS] User adjudication */
\r
5619 case IDM_UserAdjudication_White:
\r
5620 UserAdjudicationEvent( +1 );
\r
5623 case IDM_UserAdjudication_Black:
\r
5624 UserAdjudicationEvent( -1 );
\r
5627 case IDM_UserAdjudication_Draw:
\r
5628 UserAdjudicationEvent( 0 );
\r
5631 /* [AS] Game list options dialog */
\r
5632 case IDM_GameListOptions:
\r
5633 GameListOptions();
\r
5640 case IDM_CopyPosition:
\r
5641 CopyFENToClipboard();
\r
5644 case IDM_PastePosition:
\r
5645 PasteFENFromClipboard();
\r
5648 case IDM_MailMove:
\r
5652 case IDM_ReloadCMailMsg:
\r
5653 Reset(TRUE, TRUE);
\r
5654 ReloadCmailMsgEvent(FALSE);
\r
5657 case IDM_Minimize:
\r
5658 ShowWindow(hwnd, SW_MINIMIZE);
\r
5665 case IDM_MachineWhite:
\r
5666 MachineWhiteEvent();
\r
5668 * refresh the tags dialog only if it's visible
\r
5670 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5672 tags = PGNTags(&gameInfo);
\r
5673 TagsPopUp(tags, CmailMsg());
\r
5676 SAY("computer starts playing white");
\r
5679 case IDM_MachineBlack:
\r
5680 MachineBlackEvent();
\r
5682 * refresh the tags dialog only if it's visible
\r
5684 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5686 tags = PGNTags(&gameInfo);
\r
5687 TagsPopUp(tags, CmailMsg());
\r
5690 SAY("computer starts playing black");
\r
5693 case IDM_TwoMachines:
\r
5694 TwoMachinesEvent();
\r
5696 * refresh the tags dialog only if it's visible
\r
5698 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5700 tags = PGNTags(&gameInfo);
\r
5701 TagsPopUp(tags, CmailMsg());
\r
5704 SAY("programs start playing each other");
\r
5707 case IDM_AnalysisMode:
\r
5708 if (!first.analysisSupport) {
\r
5709 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5710 DisplayError(buf, 0);
\r
5712 SAY("analyzing current position");
\r
5713 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5714 if (appData.icsActive) {
\r
5715 if (gameMode != IcsObserving) {
\r
5716 sprintf(buf, "You are not observing a game");
\r
5717 DisplayError(buf, 0);
\r
5718 /* secure check */
\r
5719 if (appData.icsEngineAnalyze) {
\r
5720 if (appData.debugMode)
\r
5721 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5722 ExitAnalyzeMode();
\r
5728 /* if enable, user want disable icsEngineAnalyze */
\r
5729 if (appData.icsEngineAnalyze) {
\r
5730 ExitAnalyzeMode();
\r
5734 appData.icsEngineAnalyze = TRUE;
\r
5735 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5738 if (!appData.showThinking) ToggleShowThinking();
\r
5739 AnalyzeModeEvent();
\r
5743 case IDM_AnalyzeFile:
\r
5744 if (!first.analysisSupport) {
\r
5745 char buf[MSG_SIZ];
\r
5746 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5747 DisplayError(buf, 0);
\r
5749 if (!appData.showThinking) ToggleShowThinking();
\r
5750 AnalyzeFileEvent();
\r
5751 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5752 AnalysisPeriodicEvent(1);
\r
5756 case IDM_IcsClient:
\r
5760 case IDM_EditGame:
\r
5765 case IDM_EditPosition:
\r
5766 EditPositionEvent();
\r
5767 SAY("to set up a position type a FEN");
\r
5770 case IDM_Training:
\r
5774 case IDM_ShowGameList:
\r
5775 ShowGameListProc();
\r
5778 case IDM_EditTags:
\r
5782 case IDM_EditComment:
\r
5783 if (commentUp && editComment) {
\r
5786 EditCommentEvent();
\r
5806 case IDM_CallFlag:
\r
5826 case IDM_StopObserving:
\r
5827 StopObservingEvent();
\r
5830 case IDM_StopExamining:
\r
5831 StopExaminingEvent();
\r
5834 case IDM_TypeInMove:
\r
5835 PopUpMoveDialog('\000');
\r
5838 case IDM_TypeInName:
\r
5839 PopUpNameDialog('\000');
\r
5842 case IDM_Backward:
\r
5844 SetFocus(hwndMain);
\r
5851 SetFocus(hwndMain);
\r
5856 SetFocus(hwndMain);
\r
5861 SetFocus(hwndMain);
\r
5868 case IDM_TruncateGame:
\r
5869 TruncateGameEvent();
\r
5876 case IDM_RetractMove:
\r
5877 RetractMoveEvent();
\r
5880 case IDM_FlipView:
\r
5881 flipView = !flipView;
\r
5882 DrawPosition(FALSE, NULL);
\r
5885 case IDM_FlipClock:
\r
5886 flipClock = !flipClock;
\r
5887 DisplayBothClocks();
\r
5888 DrawPosition(FALSE, NULL);
\r
5891 case IDM_MuteSounds:
\r
5892 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5893 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5894 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5897 case IDM_GeneralOptions:
\r
5898 GeneralOptionsPopup(hwnd);
\r
5899 DrawPosition(TRUE, NULL);
\r
5902 case IDM_BoardOptions:
\r
5903 BoardOptionsPopup(hwnd);
\r
5906 case IDM_EnginePlayOptions:
\r
5907 EnginePlayOptionsPopup(hwnd);
\r
5910 case IDM_Engine1Options:
\r
5911 EngineOptionsPopup(hwnd, &first);
\r
5914 case IDM_Engine2Options:
\r
5915 EngineOptionsPopup(hwnd, &second);
\r
5918 case IDM_OptionsUCI:
\r
5919 UciOptionsPopup(hwnd);
\r
5922 case IDM_IcsOptions:
\r
5923 IcsOptionsPopup(hwnd);
\r
5927 FontsOptionsPopup(hwnd);
\r
5931 SoundOptionsPopup(hwnd);
\r
5934 case IDM_CommPort:
\r
5935 CommPortOptionsPopup(hwnd);
\r
5938 case IDM_LoadOptions:
\r
5939 LoadOptionsPopup(hwnd);
\r
5942 case IDM_SaveOptions:
\r
5943 SaveOptionsPopup(hwnd);
\r
5946 case IDM_TimeControl:
\r
5947 TimeControlOptionsPopup(hwnd);
\r
5950 case IDM_SaveSettings:
\r
5951 SaveSettings(settingsFileName);
\r
5954 case IDM_SaveSettingsOnExit:
\r
5955 saveSettingsOnExit = !saveSettingsOnExit;
\r
5956 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5957 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5958 MF_CHECKED : MF_UNCHECKED));
\r
5969 case IDM_AboutGame:
\r
5974 appData.debugMode = !appData.debugMode;
\r
5975 if (appData.debugMode) {
\r
5976 char dir[MSG_SIZ];
\r
5977 GetCurrentDirectory(MSG_SIZ, dir);
\r
5978 SetCurrentDirectory(installDir);
\r
5979 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5980 SetCurrentDirectory(dir);
\r
5981 setbuf(debugFP, NULL);
\r
5988 case IDM_HELPCONTENTS:
\r
5989 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5990 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5991 MessageBox (GetFocus(),
\r
5992 "Unable to activate help",
\r
5993 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5997 case IDM_HELPSEARCH:
\r
5998 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5999 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6000 MessageBox (GetFocus(),
\r
6001 "Unable to activate help",
\r
6002 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6006 case IDM_HELPHELP:
\r
6007 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6008 MessageBox (GetFocus(),
\r
6009 "Unable to activate help",
\r
6010 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6015 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6017 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6018 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6019 FreeProcInstance(lpProc);
\r
6022 case IDM_DirectCommand1:
\r
6023 AskQuestionEvent("Direct Command",
\r
6024 "Send to chess program:", "", "1");
\r
6026 case IDM_DirectCommand2:
\r
6027 AskQuestionEvent("Direct Command",
\r
6028 "Send to second chess program:", "", "2");
\r
6031 case EP_WhitePawn:
\r
6032 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6033 fromX = fromY = -1;
\r
6036 case EP_WhiteKnight:
\r
6037 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6038 fromX = fromY = -1;
\r
6041 case EP_WhiteBishop:
\r
6042 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6043 fromX = fromY = -1;
\r
6046 case EP_WhiteRook:
\r
6047 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6048 fromX = fromY = -1;
\r
6051 case EP_WhiteQueen:
\r
6052 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6053 fromX = fromY = -1;
\r
6056 case EP_WhiteFerz:
\r
6057 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6058 fromX = fromY = -1;
\r
6061 case EP_WhiteWazir:
\r
6062 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6063 fromX = fromY = -1;
\r
6066 case EP_WhiteAlfil:
\r
6067 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6068 fromX = fromY = -1;
\r
6071 case EP_WhiteCannon:
\r
6072 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6073 fromX = fromY = -1;
\r
6076 case EP_WhiteCardinal:
\r
6077 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6078 fromX = fromY = -1;
\r
6081 case EP_WhiteMarshall:
\r
6082 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6083 fromX = fromY = -1;
\r
6086 case EP_WhiteKing:
\r
6087 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6088 fromX = fromY = -1;
\r
6091 case EP_BlackPawn:
\r
6092 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6093 fromX = fromY = -1;
\r
6096 case EP_BlackKnight:
\r
6097 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6098 fromX = fromY = -1;
\r
6101 case EP_BlackBishop:
\r
6102 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6103 fromX = fromY = -1;
\r
6106 case EP_BlackRook:
\r
6107 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6108 fromX = fromY = -1;
\r
6111 case EP_BlackQueen:
\r
6112 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6113 fromX = fromY = -1;
\r
6116 case EP_BlackFerz:
\r
6117 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6118 fromX = fromY = -1;
\r
6121 case EP_BlackWazir:
\r
6122 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6123 fromX = fromY = -1;
\r
6126 case EP_BlackAlfil:
\r
6127 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6128 fromX = fromY = -1;
\r
6131 case EP_BlackCannon:
\r
6132 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6133 fromX = fromY = -1;
\r
6136 case EP_BlackCardinal:
\r
6137 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6138 fromX = fromY = -1;
\r
6141 case EP_BlackMarshall:
\r
6142 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6143 fromX = fromY = -1;
\r
6146 case EP_BlackKing:
\r
6147 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6148 fromX = fromY = -1;
\r
6151 case EP_EmptySquare:
\r
6152 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6153 fromX = fromY = -1;
\r
6156 case EP_ClearBoard:
\r
6157 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6158 fromX = fromY = -1;
\r
6162 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6163 fromX = fromY = -1;
\r
6167 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6168 fromX = fromY = -1;
\r
6172 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6173 fromX = fromY = -1;
\r
6177 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6178 fromX = fromY = -1;
\r
6182 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6183 fromX = fromY = -1;
\r
6187 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6188 fromX = fromY = -1;
\r
6192 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6193 fromX = fromY = -1;
\r
6197 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6198 fromX = fromY = -1;
\r
6202 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6203 fromX = fromY = -1;
\r
6207 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6213 case CLOCK_TIMER_ID:
\r
6214 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6215 clockTimerEvent = 0;
\r
6216 DecrementClocks(); /* call into back end */
\r
6218 case LOAD_GAME_TIMER_ID:
\r
6219 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6220 loadGameTimerEvent = 0;
\r
6221 AutoPlayGameLoop(); /* call into back end */
\r
6223 case ANALYSIS_TIMER_ID:
\r
6224 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6225 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6226 AnalysisPeriodicEvent(0);
\r
6228 KillTimer(hwnd, analysisTimerEvent);
\r
6229 analysisTimerEvent = 0;
\r
6232 case DELAYED_TIMER_ID:
\r
6233 KillTimer(hwnd, delayedTimerEvent);
\r
6234 delayedTimerEvent = 0;
\r
6235 delayedTimerCallback();
\r
6240 case WM_USER_Input:
\r
6241 InputEvent(hwnd, message, wParam, lParam);
\r
6244 /* [AS] Also move "attached" child windows */
\r
6245 case WM_WINDOWPOSCHANGING:
\r
6247 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6248 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6250 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6251 /* Window is moving */
\r
6254 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6255 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6256 rcMain.right = boardX + winWidth;
\r
6257 rcMain.top = boardY;
\r
6258 rcMain.bottom = boardY + winHeight;
\r
6260 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6261 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6262 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6263 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6264 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6271 /* [AS] Snapping */
\r
6272 case WM_ENTERSIZEMOVE:
\r
6273 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6274 if (hwnd == hwndMain) {
\r
6275 doingSizing = TRUE;
\r
6278 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6282 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6283 if (hwnd == hwndMain) {
\r
6284 lastSizing = wParam;
\r
6289 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6290 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6292 case WM_EXITSIZEMOVE:
\r
6293 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6294 if (hwnd == hwndMain) {
\r
6296 doingSizing = FALSE;
\r
6297 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6298 GetClientRect(hwnd, &client);
\r
6299 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6301 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6303 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6306 case WM_DESTROY: /* message: window being destroyed */
\r
6307 PostQuitMessage(0);
\r
6311 if (hwnd == hwndMain) {
\r
6316 default: /* Passes it on if unprocessed */
\r
6317 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6322 /*---------------------------------------------------------------------------*\
\r
6324 * Misc utility routines
\r
6326 \*---------------------------------------------------------------------------*/
\r
6329 * Decent random number generator, at least not as bad as Windows
\r
6330 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6332 unsigned int randstate;
\r
6337 randstate = randstate * 1664525 + 1013904223;
\r
6338 return (int) randstate & 0x7fffffff;
\r
6342 mysrandom(unsigned int seed)
\r
6349 * returns TRUE if user selects a different color, FALSE otherwise
\r
6353 ChangeColor(HWND hwnd, COLORREF *which)
\r
6355 static BOOL firstTime = TRUE;
\r
6356 static DWORD customColors[16];
\r
6358 COLORREF newcolor;
\r
6363 /* Make initial colors in use available as custom colors */
\r
6364 /* Should we put the compiled-in defaults here instead? */
\r
6366 customColors[i++] = lightSquareColor & 0xffffff;
\r
6367 customColors[i++] = darkSquareColor & 0xffffff;
\r
6368 customColors[i++] = whitePieceColor & 0xffffff;
\r
6369 customColors[i++] = blackPieceColor & 0xffffff;
\r
6370 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6371 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6373 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6374 customColors[i++] = textAttribs[ccl].color;
\r
6376 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6377 firstTime = FALSE;
\r
6380 cc.lStructSize = sizeof(cc);
\r
6381 cc.hwndOwner = hwnd;
\r
6382 cc.hInstance = NULL;
\r
6383 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6384 cc.lpCustColors = (LPDWORD) customColors;
\r
6385 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6387 if (!ChooseColor(&cc)) return FALSE;
\r
6389 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6390 if (newcolor == *which) return FALSE;
\r
6391 *which = newcolor;
\r
6395 InitDrawingColors();
\r
6396 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6401 MyLoadSound(MySound *ms)
\r
6407 if (ms->data) free(ms->data);
\r
6410 switch (ms->name[0]) {
\r
6416 /* System sound from Control Panel. Don't preload here. */
\r
6420 if (ms->name[1] == NULLCHAR) {
\r
6421 /* "!" alone = silence */
\r
6424 /* Builtin wave resource. Error if not found. */
\r
6425 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6426 if (h == NULL) break;
\r
6427 ms->data = (void *)LoadResource(hInst, h);
\r
6428 if (h == NULL) break;
\r
6433 /* .wav file. Error if not found. */
\r
6434 f = fopen(ms->name, "rb");
\r
6435 if (f == NULL) break;
\r
6436 if (fstat(fileno(f), &st) < 0) break;
\r
6437 ms->data = malloc(st.st_size);
\r
6438 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6444 char buf[MSG_SIZ];
\r
6445 sprintf(buf, "Error loading sound %s", ms->name);
\r
6446 DisplayError(buf, GetLastError());
\r
6452 MyPlaySound(MySound *ms)
\r
6454 BOOLEAN ok = FALSE;
\r
6456 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6457 switch (ms->name[0]) {
\r
6459 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6464 /* System sound from Control Panel (deprecated feature).
\r
6465 "$" alone or an unset sound name gets default beep (still in use). */
\r
6466 if (ms->name[1]) {
\r
6467 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6469 if (!ok) ok = MessageBeep(MB_OK);
\r
6472 /* Builtin wave resource, or "!" alone for silence */
\r
6473 if (ms->name[1]) {
\r
6474 if (ms->data == NULL) return FALSE;
\r
6475 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6481 /* .wav file. Error if not found. */
\r
6482 if (ms->data == NULL) return FALSE;
\r
6483 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6486 /* Don't print an error: this can happen innocently if the sound driver
\r
6487 is busy; for instance, if another instance of WinBoard is playing
\r
6488 a sound at about the same time. */
\r
6494 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6497 OPENFILENAME *ofn;
\r
6498 static UINT *number; /* gross that this is static */
\r
6500 switch (message) {
\r
6501 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6502 /* Center the dialog over the application window */
\r
6503 ofn = (OPENFILENAME *) lParam;
\r
6504 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6505 number = (UINT *) ofn->lCustData;
\r
6506 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6510 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6511 return FALSE; /* Allow for further processing */
\r
6514 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6515 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6517 return FALSE; /* Allow for further processing */
\r
6523 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6525 static UINT *number;
\r
6526 OPENFILENAME *ofname;
\r
6529 case WM_INITDIALOG:
\r
6530 ofname = (OPENFILENAME *)lParam;
\r
6531 number = (UINT *)(ofname->lCustData);
\r
6534 ofnot = (OFNOTIFY *)lParam;
\r
6535 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6536 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6545 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6546 char *nameFilt, char *dlgTitle, UINT *number,
\r
6547 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6549 OPENFILENAME openFileName;
\r
6550 char buf1[MSG_SIZ];
\r
6553 if (fileName == NULL) fileName = buf1;
\r
6554 if (defName == NULL) {
\r
6555 strcpy(fileName, "*.");
\r
6556 strcat(fileName, defExt);
\r
6558 strcpy(fileName, defName);
\r
6560 if (fileTitle) strcpy(fileTitle, "");
\r
6561 if (number) *number = 0;
\r
6563 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6564 openFileName.hwndOwner = hwnd;
\r
6565 openFileName.hInstance = (HANDLE) hInst;
\r
6566 openFileName.lpstrFilter = nameFilt;
\r
6567 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6568 openFileName.nMaxCustFilter = 0L;
\r
6569 openFileName.nFilterIndex = 1L;
\r
6570 openFileName.lpstrFile = fileName;
\r
6571 openFileName.nMaxFile = MSG_SIZ;
\r
6572 openFileName.lpstrFileTitle = fileTitle;
\r
6573 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6574 openFileName.lpstrInitialDir = NULL;
\r
6575 openFileName.lpstrTitle = dlgTitle;
\r
6576 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6577 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6578 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6579 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6580 openFileName.nFileOffset = 0;
\r
6581 openFileName.nFileExtension = 0;
\r
6582 openFileName.lpstrDefExt = defExt;
\r
6583 openFileName.lCustData = (LONG) number;
\r
6584 openFileName.lpfnHook = oldDialog ?
\r
6585 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6586 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6588 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6589 GetOpenFileName(&openFileName)) {
\r
6590 /* open the file */
\r
6591 f = fopen(openFileName.lpstrFile, write);
\r
6593 MessageBox(hwnd, "File open failed", NULL,
\r
6594 MB_OK|MB_ICONEXCLAMATION);
\r
6598 int err = CommDlgExtendedError();
\r
6599 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6608 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6610 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6613 * Get the first pop-up menu in the menu template. This is the
\r
6614 * menu that TrackPopupMenu displays.
\r
6616 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6618 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6621 * TrackPopup uses screen coordinates, so convert the
\r
6622 * coordinates of the mouse click to screen coordinates.
\r
6624 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6626 /* Draw and track the floating pop-up menu. */
\r
6627 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6628 pt.x, pt.y, 0, hwnd, NULL);
\r
6630 /* Destroy the menu.*/
\r
6631 DestroyMenu(hmenu);
\r
6636 int sizeX, sizeY, newSizeX, newSizeY;
\r
6638 } ResizeEditPlusButtonsClosure;
\r
6641 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6643 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6647 if (hChild == cl->hText) return TRUE;
\r
6648 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6649 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6650 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6651 ScreenToClient(cl->hDlg, &pt);
\r
6652 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6653 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6657 /* Resize a dialog that has a (rich) edit field filling most of
\r
6658 the top, with a row of buttons below */
\r
6660 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6663 int newTextHeight, newTextWidth;
\r
6664 ResizeEditPlusButtonsClosure cl;
\r
6666 /*if (IsIconic(hDlg)) return;*/
\r
6667 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6669 cl.hdwp = BeginDeferWindowPos(8);
\r
6671 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6672 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6673 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6674 if (newTextHeight < 0) {
\r
6675 newSizeY += -newTextHeight;
\r
6676 newTextHeight = 0;
\r
6678 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6679 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6685 cl.newSizeX = newSizeX;
\r
6686 cl.newSizeY = newSizeY;
\r
6687 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6689 EndDeferWindowPos(cl.hdwp);
\r
6692 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6694 RECT rChild, rParent;
\r
6695 int wChild, hChild, wParent, hParent;
\r
6696 int wScreen, hScreen, xNew, yNew;
\r
6699 /* Get the Height and Width of the child window */
\r
6700 GetWindowRect (hwndChild, &rChild);
\r
6701 wChild = rChild.right - rChild.left;
\r
6702 hChild = rChild.bottom - rChild.top;
\r
6704 /* Get the Height and Width of the parent window */
\r
6705 GetWindowRect (hwndParent, &rParent);
\r
6706 wParent = rParent.right - rParent.left;
\r
6707 hParent = rParent.bottom - rParent.top;
\r
6709 /* Get the display limits */
\r
6710 hdc = GetDC (hwndChild);
\r
6711 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6712 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6713 ReleaseDC(hwndChild, hdc);
\r
6715 /* Calculate new X position, then adjust for screen */
\r
6716 xNew = rParent.left + ((wParent - wChild) /2);
\r
6719 } else if ((xNew+wChild) > wScreen) {
\r
6720 xNew = wScreen - wChild;
\r
6723 /* Calculate new Y position, then adjust for screen */
\r
6725 yNew = rParent.top + ((hParent - hChild) /2);
\r
6728 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6733 } else if ((yNew+hChild) > hScreen) {
\r
6734 yNew = hScreen - hChild;
\r
6737 /* Set it, and return */
\r
6738 return SetWindowPos (hwndChild, NULL,
\r
6739 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6742 /* Center one window over another */
\r
6743 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6745 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6748 /*---------------------------------------------------------------------------*\
\r
6750 * Startup Dialog functions
\r
6752 \*---------------------------------------------------------------------------*/
\r
6754 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6756 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6758 while (*cd != NULL) {
\r
6759 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6765 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6767 char buf1[ARG_MAX];
\r
6770 if (str[0] == '@') {
\r
6771 FILE* f = fopen(str + 1, "r");
\r
6773 DisplayFatalError(str + 1, errno, 2);
\r
6776 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6778 buf1[len] = NULLCHAR;
\r
6782 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6785 char buf[MSG_SIZ];
\r
6786 char *end = strchr(str, '\n');
\r
6787 if (end == NULL) return;
\r
6788 memcpy(buf, str, end - str);
\r
6789 buf[end - str] = NULLCHAR;
\r
6790 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6796 SetStartupDialogEnables(HWND hDlg)
\r
6798 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6799 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6800 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6801 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6802 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6803 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6804 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6805 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6806 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6807 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6808 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6809 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6810 IsDlgButtonChecked(hDlg, OPT_View));
\r
6814 QuoteForFilename(char *filename)
\r
6816 int dquote, space;
\r
6817 dquote = strchr(filename, '"') != NULL;
\r
6818 space = strchr(filename, ' ') != NULL;
\r
6819 if (dquote || space) {
\r
6831 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6833 char buf[MSG_SIZ];
\r
6836 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6837 q = QuoteForFilename(nthcp);
\r
6838 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6839 if (*nthdir != NULLCHAR) {
\r
6840 q = QuoteForFilename(nthdir);
\r
6841 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6843 if (*nthcp == NULLCHAR) {
\r
6844 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6845 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6846 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6847 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6852 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6854 char buf[MSG_SIZ];
\r
6858 switch (message) {
\r
6859 case WM_INITDIALOG:
\r
6860 /* Center the dialog */
\r
6861 CenterWindow (hDlg, GetDesktopWindow());
\r
6862 /* Initialize the dialog items */
\r
6863 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6864 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6865 firstChessProgramNames);
\r
6866 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6867 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6868 secondChessProgramNames);
\r
6869 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6870 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6871 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6872 if (*appData.icsHelper != NULLCHAR) {
\r
6873 char *q = QuoteForFilename(appData.icsHelper);
\r
6874 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6876 if (*appData.icsHost == NULLCHAR) {
\r
6877 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6878 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6879 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6880 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6881 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6884 if (appData.icsActive) {
\r
6885 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6887 else if (appData.noChessProgram) {
\r
6888 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6891 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6894 SetStartupDialogEnables(hDlg);
\r
6898 switch (LOWORD(wParam)) {
\r
6900 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6901 strcpy(buf, "/fcp=");
\r
6902 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6904 ParseArgs(StringGet, &p);
\r
6905 strcpy(buf, "/scp=");
\r
6906 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6908 ParseArgs(StringGet, &p);
\r
6909 appData.noChessProgram = FALSE;
\r
6910 appData.icsActive = FALSE;
\r
6911 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6912 strcpy(buf, "/ics /icshost=");
\r
6913 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6915 ParseArgs(StringGet, &p);
\r
6916 if (appData.zippyPlay) {
\r
6917 strcpy(buf, "/fcp=");
\r
6918 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6920 ParseArgs(StringGet, &p);
\r
6922 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6923 appData.noChessProgram = TRUE;
\r
6924 appData.icsActive = FALSE;
\r
6926 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6927 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6930 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6931 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6933 ParseArgs(StringGet, &p);
\r
6935 EndDialog(hDlg, TRUE);
\r
6942 case IDM_HELPCONTENTS:
\r
6943 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6944 MessageBox (GetFocus(),
\r
6945 "Unable to activate help",
\r
6946 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6951 SetStartupDialogEnables(hDlg);
\r
6959 /*---------------------------------------------------------------------------*\
\r
6961 * About box dialog functions
\r
6963 \*---------------------------------------------------------------------------*/
\r
6965 /* Process messages for "About" dialog box */
\r
6967 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6969 switch (message) {
\r
6970 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6971 /* Center the dialog over the application window */
\r
6972 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6973 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6977 case WM_COMMAND: /* message: received a command */
\r
6978 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6979 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6980 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6988 /*---------------------------------------------------------------------------*\
\r
6990 * Comment Dialog functions
\r
6992 \*---------------------------------------------------------------------------*/
\r
6995 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6997 static HANDLE hwndText = NULL;
\r
6998 int len, newSizeX, newSizeY, flags;
\r
6999 static int sizeX, sizeY;
\r
7004 switch (message) {
\r
7005 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7006 /* Initialize the dialog items */
\r
7007 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7008 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7009 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7010 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7011 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7012 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7013 SetWindowText(hDlg, commentTitle);
\r
7014 if (editComment) {
\r
7015 SetFocus(hwndText);
\r
7017 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7019 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7020 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7021 MAKELPARAM(FALSE, 0));
\r
7022 /* Size and position the dialog */
\r
7023 if (!commentDialog) {
\r
7024 commentDialog = hDlg;
\r
7025 flags = SWP_NOZORDER;
\r
7026 GetClientRect(hDlg, &rect);
\r
7027 sizeX = rect.right;
\r
7028 sizeY = rect.bottom;
\r
7029 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7030 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7031 WINDOWPLACEMENT wp;
\r
7032 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7033 wp.length = sizeof(WINDOWPLACEMENT);
\r
7035 wp.showCmd = SW_SHOW;
\r
7036 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7037 wp.rcNormalPosition.left = commentX;
\r
7038 wp.rcNormalPosition.right = commentX + commentW;
\r
7039 wp.rcNormalPosition.top = commentY;
\r
7040 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7041 SetWindowPlacement(hDlg, &wp);
\r
7043 GetClientRect(hDlg, &rect);
\r
7044 newSizeX = rect.right;
\r
7045 newSizeY = rect.bottom;
\r
7046 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7047 newSizeX, newSizeY);
\r
7054 case WM_COMMAND: /* message: received a command */
\r
7055 switch (LOWORD(wParam)) {
\r
7057 if (editComment) {
\r
7059 /* Read changed options from the dialog box */
\r
7060 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7061 len = GetWindowTextLength(hwndText);
\r
7062 str = (char *) malloc(len + 1);
\r
7063 GetWindowText(hwndText, str, len + 1);
\r
7072 ReplaceComment(commentIndex, str);
\r
7079 case OPT_CancelComment:
\r
7083 case OPT_ClearComment:
\r
7084 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7087 case OPT_EditComment:
\r
7088 EditCommentEvent();
\r
7097 newSizeX = LOWORD(lParam);
\r
7098 newSizeY = HIWORD(lParam);
\r
7099 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7104 case WM_GETMINMAXINFO:
\r
7105 /* Prevent resizing window too small */
\r
7106 mmi = (MINMAXINFO *) lParam;
\r
7107 mmi->ptMinTrackSize.x = 100;
\r
7108 mmi->ptMinTrackSize.y = 100;
\r
7115 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7120 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7122 if (str == NULL) str = "";
\r
7123 p = (char *) malloc(2 * strlen(str) + 2);
\r
7126 if (*str == '\n') *q++ = '\r';
\r
7130 if (commentText != NULL) free(commentText);
\r
7132 commentIndex = index;
\r
7133 commentTitle = title;
\r
7135 editComment = edit;
\r
7137 if (commentDialog) {
\r
7138 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7139 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
7141 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7142 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7143 hwndMain, (DLGPROC)lpProc);
\r
7144 FreeProcInstance(lpProc);
\r
7150 /*---------------------------------------------------------------------------*\
\r
7152 * Type-in move dialog functions
\r
7154 \*---------------------------------------------------------------------------*/
\r
7157 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7159 char move[MSG_SIZ];
\r
7161 ChessMove moveType;
\r
7162 int fromX, fromY, toX, toY;
\r
7165 switch (message) {
\r
7166 case WM_INITDIALOG:
\r
7167 move[0] = (char) lParam;
\r
7168 move[1] = NULLCHAR;
\r
7169 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7170 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7171 SetWindowText(hInput, move);
\r
7173 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7177 switch (LOWORD(wParam)) {
\r
7179 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7180 { int n; Board board;
\r
7182 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7183 EditPositionPasteFEN(move);
\r
7184 EndDialog(hDlg, TRUE);
\r
7187 // [HGM] movenum: allow move number to be typed in any mode
\r
7188 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7189 currentMove = 2*n-1;
\r
7190 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7191 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7192 EndDialog(hDlg, TRUE);
\r
7193 DrawPosition(TRUE, boards[currentMove]);
\r
7194 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7195 else DisplayMessage("", "");
\r
7199 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7200 gameMode != Training) {
\r
7201 DisplayMoveError("Displayed move is not current");
\r
7203 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7204 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7205 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7206 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7207 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7208 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7209 if (gameMode != Training)
\r
7210 forwardMostMove = currentMove;
\r
7211 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7213 DisplayMoveError("Could not parse move");
\r
7216 EndDialog(hDlg, TRUE);
\r
7219 EndDialog(hDlg, FALSE);
\r
7230 PopUpMoveDialog(char firstchar)
\r
7234 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7235 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7236 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7237 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7238 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7239 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7240 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7241 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7242 gameMode == Training) {
\r
7243 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7244 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7245 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7246 FreeProcInstance(lpProc);
\r
7250 /*---------------------------------------------------------------------------*\
\r
7252 * Type-in name dialog functions
\r
7254 \*---------------------------------------------------------------------------*/
\r
7257 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7259 char move[MSG_SIZ];
\r
7262 switch (message) {
\r
7263 case WM_INITDIALOG:
\r
7264 move[0] = (char) lParam;
\r
7265 move[1] = NULLCHAR;
\r
7266 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7267 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7268 SetWindowText(hInput, move);
\r
7270 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7274 switch (LOWORD(wParam)) {
\r
7276 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7277 appData.userName = strdup(move);
\r
7280 EndDialog(hDlg, TRUE);
\r
7283 EndDialog(hDlg, FALSE);
\r
7294 PopUpNameDialog(char firstchar)
\r
7298 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7299 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7300 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7301 FreeProcInstance(lpProc);
\r
7304 /*---------------------------------------------------------------------------*\
\r
7308 \*---------------------------------------------------------------------------*/
\r
7310 /* Nonmodal error box */
\r
7311 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7312 WPARAM wParam, LPARAM lParam);
\r
7315 ErrorPopUp(char *title, char *content)
\r
7319 BOOLEAN modal = hwndMain == NULL;
\r
7337 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7338 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7341 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7343 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7344 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7345 hwndMain, (DLGPROC)lpProc);
\r
7346 FreeProcInstance(lpProc);
\r
7353 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7354 if (errorDialog == NULL) return;
\r
7355 DestroyWindow(errorDialog);
\r
7356 errorDialog = NULL;
\r
7360 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7365 switch (message) {
\r
7366 case WM_INITDIALOG:
\r
7367 GetWindowRect(hDlg, &rChild);
\r
7370 SetWindowPos(hDlg, NULL, rChild.left,
\r
7371 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7372 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7376 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7377 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7378 and it doesn't work when you resize the dialog.
\r
7379 For now, just give it a default position.
\r
7381 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7383 errorDialog = hDlg;
\r
7384 SetWindowText(hDlg, errorTitle);
\r
7385 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7386 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7390 switch (LOWORD(wParam)) {
\r
7393 if (errorDialog == hDlg) errorDialog = NULL;
\r
7394 DestroyWindow(hDlg);
\r
7406 HWND gothicDialog = NULL;
\r
7409 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7413 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7415 switch (message) {
\r
7416 case WM_INITDIALOG:
\r
7417 GetWindowRect(hDlg, &rChild);
\r
7419 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7423 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7424 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7425 and it doesn't work when you resize the dialog.
\r
7426 For now, just give it a default position.
\r
7428 gothicDialog = hDlg;
\r
7429 SetWindowText(hDlg, errorTitle);
\r
7430 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7431 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7435 switch (LOWORD(wParam)) {
\r
7438 if (errorDialog == hDlg) errorDialog = NULL;
\r
7439 DestroyWindow(hDlg);
\r
7451 GothicPopUp(char *title, VariantClass variant)
\r
7454 static char *lastTitle;
\r
7456 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7457 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7459 if(lastTitle != title && gothicDialog != NULL) {
\r
7460 DestroyWindow(gothicDialog);
\r
7461 gothicDialog = NULL;
\r
7463 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7464 title = lastTitle;
\r
7465 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7466 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7467 hwndMain, (DLGPROC)lpProc);
\r
7468 FreeProcInstance(lpProc);
\r
7473 /*---------------------------------------------------------------------------*\
\r
7475 * Ics Interaction console functions
\r
7477 \*---------------------------------------------------------------------------*/
\r
7479 #define HISTORY_SIZE 64
\r
7480 static char *history[HISTORY_SIZE];
\r
7481 int histIn = 0, histP = 0;
\r
7484 SaveInHistory(char *cmd)
\r
7486 if (history[histIn] != NULL) {
\r
7487 free(history[histIn]);
\r
7488 history[histIn] = NULL;
\r
7490 if (*cmd == NULLCHAR) return;
\r
7491 history[histIn] = StrSave(cmd);
\r
7492 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7493 if (history[histIn] != NULL) {
\r
7494 free(history[histIn]);
\r
7495 history[histIn] = NULL;
\r
7501 PrevInHistory(char *cmd)
\r
7504 if (histP == histIn) {
\r
7505 if (history[histIn] != NULL) free(history[histIn]);
\r
7506 history[histIn] = StrSave(cmd);
\r
7508 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7509 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7511 return history[histP];
\r
7517 if (histP == histIn) return NULL;
\r
7518 histP = (histP + 1) % HISTORY_SIZE;
\r
7519 return history[histP];
\r
7526 BOOLEAN immediate;
\r
7527 } IcsTextMenuEntry;
\r
7528 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7529 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7532 ParseIcsTextMenu(char *icsTextMenuString)
\r
7535 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7536 char *p = icsTextMenuString;
\r
7537 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7540 if (e->command != NULL) {
\r
7542 e->command = NULL;
\r
7546 e = icsTextMenuEntry;
\r
7547 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7548 if (*p == ';' || *p == '\n') {
\r
7549 e->item = strdup("-");
\r
7550 e->command = NULL;
\r
7552 } else if (*p == '-') {
\r
7553 e->item = strdup("-");
\r
7554 e->command = NULL;
\r
7558 char *q, *r, *s, *t;
\r
7560 q = strchr(p, ',');
\r
7561 if (q == NULL) break;
\r
7563 r = strchr(q + 1, ',');
\r
7564 if (r == NULL) break;
\r
7566 s = strchr(r + 1, ',');
\r
7567 if (s == NULL) break;
\r
7570 t = strchr(s + 1, c);
\r
7573 t = strchr(s + 1, c);
\r
7575 if (t != NULL) *t = NULLCHAR;
\r
7576 e->item = strdup(p);
\r
7577 e->command = strdup(q + 1);
\r
7578 e->getname = *(r + 1) != '0';
\r
7579 e->immediate = *(s + 1) != '0';
\r
7583 if (t == NULL) break;
\r
7592 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7596 hmenu = LoadMenu(hInst, "TextMenu");
\r
7597 h = GetSubMenu(hmenu, 0);
\r
7599 if (strcmp(e->item, "-") == 0) {
\r
7600 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7602 if (e->item[0] == '|') {
\r
7603 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7604 IDM_CommandX + i, &e->item[1]);
\r
7606 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7615 WNDPROC consoleTextWindowProc;
\r
7618 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7620 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7621 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7625 SetWindowText(hInput, command);
\r
7627 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7629 sel.cpMin = 999999;
\r
7630 sel.cpMax = 999999;
\r
7631 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7636 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7637 if (sel.cpMin == sel.cpMax) {
\r
7638 /* Expand to surrounding word */
\r
7641 tr.chrg.cpMax = sel.cpMin;
\r
7642 tr.chrg.cpMin = --sel.cpMin;
\r
7643 if (sel.cpMin < 0) break;
\r
7644 tr.lpstrText = name;
\r
7645 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7646 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7650 tr.chrg.cpMin = sel.cpMax;
\r
7651 tr.chrg.cpMax = ++sel.cpMax;
\r
7652 tr.lpstrText = name;
\r
7653 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7654 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7657 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7658 MessageBeep(MB_ICONEXCLAMATION);
\r
7662 tr.lpstrText = name;
\r
7663 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7665 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7666 MessageBeep(MB_ICONEXCLAMATION);
\r
7669 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7672 sprintf(buf, "%s %s", command, name);
\r
7673 SetWindowText(hInput, buf);
\r
7674 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7676 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7677 SetWindowText(hInput, buf);
\r
7678 sel.cpMin = 999999;
\r
7679 sel.cpMax = 999999;
\r
7680 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7686 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7691 switch (message) {
\r
7693 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7696 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7699 sel.cpMin = 999999;
\r
7700 sel.cpMax = 999999;
\r
7701 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7702 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7707 if(wParam != '\022') {
\r
7708 if (wParam == '\t') {
\r
7709 if (GetKeyState(VK_SHIFT) < 0) {
\r
7711 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7712 if (buttonDesc[0].hwnd) {
\r
7713 SetFocus(buttonDesc[0].hwnd);
\r
7715 SetFocus(hwndMain);
\r
7719 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7722 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7723 JAWS_DELETE( SetFocus(hInput); )
\r
7724 SendMessage(hInput, message, wParam, lParam);
\r
7727 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7728 case WM_RBUTTONUP:
\r
7729 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7730 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7731 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7734 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7735 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7736 if (sel.cpMin == sel.cpMax) {
\r
7737 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7738 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7740 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7741 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7743 pt.x = LOWORD(lParam);
\r
7744 pt.y = HIWORD(lParam);
\r
7745 MenuPopup(hwnd, pt, hmenu, -1);
\r
7749 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7751 return SendMessage(hInput, message, wParam, lParam);
\r
7752 case WM_MBUTTONDOWN:
\r
7753 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7754 case WM_RBUTTONDOWN:
\r
7755 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7756 /* Move selection here if it was empty */
\r
7758 pt.x = LOWORD(lParam);
\r
7759 pt.y = HIWORD(lParam);
\r
7760 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7761 if (sel.cpMin == sel.cpMax) {
\r
7762 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7763 sel.cpMax = sel.cpMin;
\r
7764 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7766 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7770 switch (LOWORD(wParam)) {
\r
7771 case IDM_QuickPaste:
\r
7773 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7774 if (sel.cpMin == sel.cpMax) {
\r
7775 MessageBeep(MB_ICONEXCLAMATION);
\r
7778 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7779 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7780 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7785 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7788 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7791 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7795 int i = LOWORD(wParam) - IDM_CommandX;
\r
7796 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7797 icsTextMenuEntry[i].command != NULL) {
\r
7798 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7799 icsTextMenuEntry[i].getname,
\r
7800 icsTextMenuEntry[i].immediate);
\r
7808 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7811 WNDPROC consoleInputWindowProc;
\r
7814 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7816 char buf[MSG_SIZ];
\r
7818 static BOOL sendNextChar = FALSE;
\r
7819 static BOOL quoteNextChar = FALSE;
\r
7820 InputSource *is = consoleInputSource;
\r
7824 switch (message) {
\r
7826 if (!appData.localLineEditing || sendNextChar) {
\r
7827 is->buf[0] = (CHAR) wParam;
\r
7829 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7830 sendNextChar = FALSE;
\r
7833 if (quoteNextChar) {
\r
7834 buf[0] = (char) wParam;
\r
7835 buf[1] = NULLCHAR;
\r
7836 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7837 quoteNextChar = FALSE;
\r
7841 case '\r': /* Enter key */
\r
7842 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7843 if (consoleEcho) SaveInHistory(is->buf);
\r
7844 is->buf[is->count++] = '\n';
\r
7845 is->buf[is->count] = NULLCHAR;
\r
7846 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7847 if (consoleEcho) {
\r
7848 ConsoleOutput(is->buf, is->count, TRUE);
\r
7849 } else if (appData.localLineEditing) {
\r
7850 ConsoleOutput("\n", 1, TRUE);
\r
7853 case '\033': /* Escape key */
\r
7854 SetWindowText(hwnd, "");
\r
7855 cf.cbSize = sizeof(CHARFORMAT);
\r
7856 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7857 if (consoleEcho) {
\r
7858 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7860 cf.crTextColor = COLOR_ECHOOFF;
\r
7862 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7863 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7865 case '\t': /* Tab key */
\r
7866 if (GetKeyState(VK_SHIFT) < 0) {
\r
7868 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7871 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7872 if (buttonDesc[0].hwnd) {
\r
7873 SetFocus(buttonDesc[0].hwnd);
\r
7875 SetFocus(hwndMain);
\r
7879 case '\023': /* Ctrl+S */
\r
7880 sendNextChar = TRUE;
\r
7882 case '\021': /* Ctrl+Q */
\r
7883 quoteNextChar = TRUE;
\r
7893 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7894 p = PrevInHistory(buf);
\r
7896 SetWindowText(hwnd, p);
\r
7897 sel.cpMin = 999999;
\r
7898 sel.cpMax = 999999;
\r
7899 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7904 p = NextInHistory();
\r
7906 SetWindowText(hwnd, p);
\r
7907 sel.cpMin = 999999;
\r
7908 sel.cpMax = 999999;
\r
7909 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7915 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7919 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7923 case WM_MBUTTONDOWN:
\r
7924 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7925 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7927 case WM_RBUTTONUP:
\r
7928 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7929 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7930 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7934 hmenu = LoadMenu(hInst, "InputMenu");
\r
7935 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7936 if (sel.cpMin == sel.cpMax) {
\r
7937 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7938 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7940 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7941 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7943 pt.x = LOWORD(lParam);
\r
7944 pt.y = HIWORD(lParam);
\r
7945 MenuPopup(hwnd, pt, hmenu, -1);
\r
7949 switch (LOWORD(wParam)) {
\r
7951 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7953 case IDM_SelectAll:
\r
7955 sel.cpMax = -1; /*999999?*/
\r
7956 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7959 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7962 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7965 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7970 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7973 #define CO_MAX 100000
\r
7974 #define CO_TRIM 1000
\r
7977 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7979 static SnapData sd;
\r
7980 HWND hText, hInput;
\r
7982 static int sizeX, sizeY;
\r
7983 int newSizeX, newSizeY;
\r
7987 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7988 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7990 switch (message) {
\r
7992 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7994 ENLINK *pLink = (ENLINK*)lParam;
\r
7995 if (pLink->msg == WM_LBUTTONUP)
\r
7999 tr.chrg = pLink->chrg;
\r
8000 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8001 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8002 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8003 free(tr.lpstrText);
\r
8007 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8008 hwndConsole = hDlg;
\r
8010 consoleTextWindowProc = (WNDPROC)
\r
8011 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8012 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8013 consoleInputWindowProc = (WNDPROC)
\r
8014 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8015 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8016 Colorize(ColorNormal, TRUE);
\r
8017 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8018 ChangedConsoleFont();
\r
8019 GetClientRect(hDlg, &rect);
\r
8020 sizeX = rect.right;
\r
8021 sizeY = rect.bottom;
\r
8022 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8023 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8024 WINDOWPLACEMENT wp;
\r
8025 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8026 wp.length = sizeof(WINDOWPLACEMENT);
\r
8028 wp.showCmd = SW_SHOW;
\r
8029 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8030 wp.rcNormalPosition.left = wpConsole.x;
\r
8031 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8032 wp.rcNormalPosition.top = wpConsole.y;
\r
8033 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8034 SetWindowPlacement(hDlg, &wp);
\r
8037 // [HGM] Chessknight's change 2004-07-13
\r
8038 else { /* Determine Defaults */
\r
8039 WINDOWPLACEMENT wp;
\r
8040 wpConsole.x = winWidth + 1;
\r
8041 wpConsole.y = boardY;
\r
8042 wpConsole.width = screenWidth - winWidth;
\r
8043 wpConsole.height = winHeight;
\r
8044 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8045 wp.length = sizeof(WINDOWPLACEMENT);
\r
8047 wp.showCmd = SW_SHOW;
\r
8048 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8049 wp.rcNormalPosition.left = wpConsole.x;
\r
8050 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8051 wp.rcNormalPosition.top = wpConsole.y;
\r
8052 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8053 SetWindowPlacement(hDlg, &wp);
\r
8056 // Allow hText to highlight URLs and send notifications on them
\r
8057 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8058 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8059 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8060 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
8074 if (IsIconic(hDlg)) break;
\r
8075 newSizeX = LOWORD(lParam);
\r
8076 newSizeY = HIWORD(lParam);
\r
8077 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8078 RECT rectText, rectInput;
\r
8080 int newTextHeight, newTextWidth;
\r
8081 GetWindowRect(hText, &rectText);
\r
8082 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8083 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8084 if (newTextHeight < 0) {
\r
8085 newSizeY += -newTextHeight;
\r
8086 newTextHeight = 0;
\r
8088 SetWindowPos(hText, NULL, 0, 0,
\r
8089 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8090 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8091 pt.x = rectInput.left;
\r
8092 pt.y = rectInput.top + newSizeY - sizeY;
\r
8093 ScreenToClient(hDlg, &pt);
\r
8094 SetWindowPos(hInput, NULL,
\r
8095 pt.x, pt.y, /* needs client coords */
\r
8096 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8097 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8103 case WM_GETMINMAXINFO:
\r
8104 /* Prevent resizing window too small */
\r
8105 mmi = (MINMAXINFO *) lParam;
\r
8106 mmi->ptMinTrackSize.x = 100;
\r
8107 mmi->ptMinTrackSize.y = 100;
\r
8110 /* [AS] Snapping */
\r
8111 case WM_ENTERSIZEMOVE:
\r
8112 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8115 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8118 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8120 case WM_EXITSIZEMOVE:
\r
8121 UpdateICSWidth(hText);
\r
8122 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8125 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8133 if (hwndConsole) return;
\r
8134 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8135 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8140 ConsoleOutput(char* data, int length, int forceVisible)
\r
8145 char buf[CO_MAX+1];
\r
8148 static int delayLF = 0;
\r
8149 CHARRANGE savesel, sel;
\r
8151 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8159 while (length--) {
\r
8167 } else if (*p == '\007') {
\r
8168 MyPlaySound(&sounds[(int)SoundBell]);
\r
8175 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8176 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8177 /* Save current selection */
\r
8178 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8179 exlen = GetWindowTextLength(hText);
\r
8180 /* Find out whether current end of text is visible */
\r
8181 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8182 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8183 /* Trim existing text if it's too long */
\r
8184 if (exlen + (q - buf) > CO_MAX) {
\r
8185 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8188 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8189 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8191 savesel.cpMin -= trim;
\r
8192 savesel.cpMax -= trim;
\r
8193 if (exlen < 0) exlen = 0;
\r
8194 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8195 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8197 /* Append the new text */
\r
8198 sel.cpMin = exlen;
\r
8199 sel.cpMax = exlen;
\r
8200 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8201 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8202 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8203 if (forceVisible || exlen == 0 ||
\r
8204 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8205 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8206 /* Scroll to make new end of text visible if old end of text
\r
8207 was visible or new text is an echo of user typein */
\r
8208 sel.cpMin = 9999999;
\r
8209 sel.cpMax = 9999999;
\r
8210 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8211 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8212 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8213 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8215 if (savesel.cpMax == exlen || forceVisible) {
\r
8216 /* Move insert point to new end of text if it was at the old
\r
8217 end of text or if the new text is an echo of user typein */
\r
8218 sel.cpMin = 9999999;
\r
8219 sel.cpMax = 9999999;
\r
8220 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8222 /* Restore previous selection */
\r
8223 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8225 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8232 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8236 COLORREF oldFg, oldBg;
\r
8240 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8242 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8243 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8244 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8247 rect.right = x + squareSize;
\r
8249 rect.bottom = y + squareSize;
\r
8252 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8253 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8254 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8255 &rect, str, strlen(str), NULL);
\r
8257 (void) SetTextColor(hdc, oldFg);
\r
8258 (void) SetBkColor(hdc, oldBg);
\r
8259 (void) SelectObject(hdc, oldFont);
\r
8263 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8264 RECT *rect, char *color, char *flagFell)
\r
8268 COLORREF oldFg, oldBg;
\r
8271 if (appData.clockMode) {
\r
8273 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8275 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8282 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8283 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8285 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8286 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8288 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8292 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8293 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8294 rect, str, strlen(str), NULL);
\r
8295 if(logoHeight > 0 && appData.clockMode) {
\r
8297 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8298 r.top = rect->top + logoHeight/2;
\r
8299 r.left = rect->left;
\r
8300 r.right = rect->right;
\r
8301 r.bottom = rect->bottom;
\r
8302 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8303 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8304 &r, str, strlen(str), NULL);
\r
8306 (void) SetTextColor(hdc, oldFg);
\r
8307 (void) SetBkColor(hdc, oldBg);
\r
8308 (void) SelectObject(hdc, oldFont);
\r
8313 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8319 if( count <= 0 ) {
\r
8320 if (appData.debugMode) {
\r
8321 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8324 return ERROR_INVALID_USER_BUFFER;
\r
8327 ResetEvent(ovl->hEvent);
\r
8328 ovl->Offset = ovl->OffsetHigh = 0;
\r
8329 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8333 err = GetLastError();
\r
8334 if (err == ERROR_IO_PENDING) {
\r
8335 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8339 err = GetLastError();
\r
8346 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8351 ResetEvent(ovl->hEvent);
\r
8352 ovl->Offset = ovl->OffsetHigh = 0;
\r
8353 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8357 err = GetLastError();
\r
8358 if (err == ERROR_IO_PENDING) {
\r
8359 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8363 err = GetLastError();
\r
8369 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8370 void CheckForInputBufferFull( InputSource * is )
\r
8372 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8373 /* Look for end of line */
\r
8374 char * p = is->buf;
\r
8376 while( p < is->next && *p != '\n' ) {
\r
8380 if( p >= is->next ) {
\r
8381 if (appData.debugMode) {
\r
8382 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8385 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8386 is->count = (DWORD) -1;
\r
8387 is->next = is->buf;
\r
8393 InputThread(LPVOID arg)
\r
8398 is = (InputSource *) arg;
\r
8399 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8400 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8401 while (is->hThread != NULL) {
\r
8402 is->error = DoReadFile(is->hFile, is->next,
\r
8403 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8404 &is->count, &ovl);
\r
8405 if (is->error == NO_ERROR) {
\r
8406 is->next += is->count;
\r
8408 if (is->error == ERROR_BROKEN_PIPE) {
\r
8409 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8412 is->count = (DWORD) -1;
\r
8413 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8418 CheckForInputBufferFull( is );
\r
8420 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8422 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8424 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8427 CloseHandle(ovl.hEvent);
\r
8428 CloseHandle(is->hFile);
\r
8430 if (appData.debugMode) {
\r
8431 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8438 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8440 NonOvlInputThread(LPVOID arg)
\r
8447 is = (InputSource *) arg;
\r
8448 while (is->hThread != NULL) {
\r
8449 is->error = ReadFile(is->hFile, is->next,
\r
8450 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8451 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8452 if (is->error == NO_ERROR) {
\r
8453 /* Change CRLF to LF */
\r
8454 if (is->next > is->buf) {
\r
8456 i = is->count + 1;
\r
8464 if (prev == '\r' && *p == '\n') {
\r
8476 if (is->error == ERROR_BROKEN_PIPE) {
\r
8477 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8480 is->count = (DWORD) -1;
\r
8484 CheckForInputBufferFull( is );
\r
8486 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8488 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8490 if (is->count < 0) break; /* Quit on error */
\r
8492 CloseHandle(is->hFile);
\r
8497 SocketInputThread(LPVOID arg)
\r
8501 is = (InputSource *) arg;
\r
8502 while (is->hThread != NULL) {
\r
8503 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8504 if ((int)is->count == SOCKET_ERROR) {
\r
8505 is->count = (DWORD) -1;
\r
8506 is->error = WSAGetLastError();
\r
8508 is->error = NO_ERROR;
\r
8509 is->next += is->count;
\r
8510 if (is->count == 0 && is->second == is) {
\r
8511 /* End of file on stderr; quit with no message */
\r
8515 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8517 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8519 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8525 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8529 is = (InputSource *) lParam;
\r
8530 if (is->lineByLine) {
\r
8531 /* Feed in lines one by one */
\r
8532 char *p = is->buf;
\r
8534 while (q < is->next) {
\r
8535 if (*q++ == '\n') {
\r
8536 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8541 /* Move any partial line to the start of the buffer */
\r
8543 while (p < is->next) {
\r
8548 if (is->error != NO_ERROR || is->count == 0) {
\r
8549 /* Notify backend of the error. Note: If there was a partial
\r
8550 line at the end, it is not flushed through. */
\r
8551 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8554 /* Feed in the whole chunk of input at once */
\r
8555 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8556 is->next = is->buf;
\r
8560 /*---------------------------------------------------------------------------*\
\r
8562 * Menu enables. Used when setting various modes.
\r
8564 \*---------------------------------------------------------------------------*/
\r
8572 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8574 while (enab->item > 0) {
\r
8575 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8580 Enables gnuEnables[] = {
\r
8581 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8595 Enables icsEnables[] = {
\r
8596 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8603 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8609 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8615 Enables zippyEnables[] = {
\r
8616 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8617 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8618 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8619 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8624 Enables ncpEnables[] = {
\r
8625 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8626 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8627 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8628 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8629 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8630 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8631 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8632 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8633 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8634 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8640 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8647 Enables trainingOnEnables[] = {
\r
8648 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8652 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8659 Enables trainingOffEnables[] = {
\r
8660 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8661 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8662 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8663 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8664 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8671 /* These modify either ncpEnables or gnuEnables */
\r
8672 Enables cmailEnables[] = {
\r
8673 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8675 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8676 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8677 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8678 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8679 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8683 Enables machineThinkingEnables[] = {
\r
8684 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8685 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8686 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8687 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8688 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8689 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8690 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8691 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8692 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8693 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8694 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8695 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8696 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8697 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8698 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8702 Enables userThinkingEnables[] = {
\r
8703 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8704 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8705 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8706 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8707 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8708 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8709 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8710 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8711 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8712 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8713 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8714 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8715 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8716 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8717 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8721 /*---------------------------------------------------------------------------*\
\r
8723 * Front-end interface functions exported by XBoard.
\r
8724 * Functions appear in same order as prototypes in frontend.h.
\r
8726 \*---------------------------------------------------------------------------*/
\r
8730 static UINT prevChecked = 0;
\r
8731 static int prevPausing = 0;
\r
8734 if (pausing != prevPausing) {
\r
8735 prevPausing = pausing;
\r
8736 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8737 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8738 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8741 switch (gameMode) {
\r
8742 case BeginningOfGame:
\r
8743 if (appData.icsActive)
\r
8744 nowChecked = IDM_IcsClient;
\r
8745 else if (appData.noChessProgram)
\r
8746 nowChecked = IDM_EditGame;
\r
8748 nowChecked = IDM_MachineBlack;
\r
8750 case MachinePlaysBlack:
\r
8751 nowChecked = IDM_MachineBlack;
\r
8753 case MachinePlaysWhite:
\r
8754 nowChecked = IDM_MachineWhite;
\r
8756 case TwoMachinesPlay:
\r
8757 nowChecked = IDM_TwoMachines;
\r
8760 nowChecked = IDM_AnalysisMode;
\r
8763 nowChecked = IDM_AnalyzeFile;
\r
8766 nowChecked = IDM_EditGame;
\r
8768 case PlayFromGameFile:
\r
8769 nowChecked = IDM_LoadGame;
\r
8771 case EditPosition:
\r
8772 nowChecked = IDM_EditPosition;
\r
8775 nowChecked = IDM_Training;
\r
8777 case IcsPlayingWhite:
\r
8778 case IcsPlayingBlack:
\r
8779 case IcsObserving:
\r
8781 nowChecked = IDM_IcsClient;
\r
8788 if (prevChecked != 0)
\r
8789 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8790 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8791 if (nowChecked != 0)
\r
8792 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8793 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8795 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8796 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8797 MF_BYCOMMAND|MF_ENABLED);
\r
8799 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8800 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8803 prevChecked = nowChecked;
\r
8805 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8806 if (appData.icsActive) {
\r
8807 if (appData.icsEngineAnalyze) {
\r
8808 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8809 MF_BYCOMMAND|MF_CHECKED);
\r
8811 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8812 MF_BYCOMMAND|MF_UNCHECKED);
\r
8820 HMENU hmenu = GetMenu(hwndMain);
\r
8821 SetMenuEnables(hmenu, icsEnables);
\r
8822 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8823 MF_BYPOSITION|MF_ENABLED);
\r
8825 if (appData.zippyPlay) {
\r
8826 SetMenuEnables(hmenu, zippyEnables);
\r
8827 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8828 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8829 MF_BYCOMMAND|MF_ENABLED);
\r
8837 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8843 HMENU hmenu = GetMenu(hwndMain);
\r
8844 SetMenuEnables(hmenu, ncpEnables);
\r
8845 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8846 MF_BYPOSITION|MF_GRAYED);
\r
8847 DrawMenuBar(hwndMain);
\r
8853 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8857 SetTrainingModeOn()
\r
8860 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8861 for (i = 0; i < N_BUTTONS; i++) {
\r
8862 if (buttonDesc[i].hwnd != NULL)
\r
8863 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8868 VOID SetTrainingModeOff()
\r
8871 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8872 for (i = 0; i < N_BUTTONS; i++) {
\r
8873 if (buttonDesc[i].hwnd != NULL)
\r
8874 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8880 SetUserThinkingEnables()
\r
8882 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8886 SetMachineThinkingEnables()
\r
8888 HMENU hMenu = GetMenu(hwndMain);
\r
8889 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8891 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8893 if (gameMode == MachinePlaysBlack) {
\r
8894 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8895 } else if (gameMode == MachinePlaysWhite) {
\r
8896 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8897 } else if (gameMode == TwoMachinesPlay) {
\r
8898 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8904 DisplayTitle(char *str)
\r
8906 char title[MSG_SIZ], *host;
\r
8907 if (str[0] != NULLCHAR) {
\r
8908 strcpy(title, str);
\r
8909 } else if (appData.icsActive) {
\r
8910 if (appData.icsCommPort[0] != NULLCHAR)
\r
8913 host = appData.icsHost;
\r
8914 sprintf(title, "%s: %s", szTitle, host);
\r
8915 } else if (appData.noChessProgram) {
\r
8916 strcpy(title, szTitle);
\r
8918 strcpy(title, szTitle);
\r
8919 strcat(title, ": ");
\r
8920 strcat(title, first.tidy);
\r
8922 SetWindowText(hwndMain, title);
\r
8927 DisplayMessage(char *str1, char *str2)
\r
8931 int remain = MESSAGE_TEXT_MAX - 1;
\r
8934 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8935 messageText[0] = NULLCHAR;
\r
8937 len = strlen(str1);
\r
8938 if (len > remain) len = remain;
\r
8939 strncpy(messageText, str1, len);
\r
8940 messageText[len] = NULLCHAR;
\r
8943 if (*str2 && remain >= 2) {
\r
8945 strcat(messageText, " ");
\r
8948 len = strlen(str2);
\r
8949 if (len > remain) len = remain;
\r
8950 strncat(messageText, str2, len);
\r
8952 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8954 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8958 hdc = GetDC(hwndMain);
\r
8959 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8960 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8961 &messageRect, messageText, strlen(messageText), NULL);
\r
8962 (void) SelectObject(hdc, oldFont);
\r
8963 (void) ReleaseDC(hwndMain, hdc);
\r
8967 DisplayError(char *str, int error)
\r
8969 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8975 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8976 NULL, error, LANG_NEUTRAL,
\r
8977 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8979 sprintf(buf, "%s:\n%s", str, buf2);
\r
8981 ErrorMap *em = errmap;
\r
8982 while (em->err != 0 && em->err != error) em++;
\r
8983 if (em->err != 0) {
\r
8984 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8986 sprintf(buf, "%s:\nError code %d", str, error);
\r
8991 ErrorPopUp("Error", buf);
\r
8996 DisplayMoveError(char *str)
\r
8998 fromX = fromY = -1;
\r
8999 ClearHighlights();
\r
9000 DrawPosition(FALSE, NULL);
\r
9001 if (appData.popupMoveErrors) {
\r
9002 ErrorPopUp("Error", str);
\r
9004 DisplayMessage(str, "");
\r
9005 moveErrorMessageUp = TRUE;
\r
9010 DisplayFatalError(char *str, int error, int exitStatus)
\r
9012 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9014 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9017 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9018 NULL, error, LANG_NEUTRAL,
\r
9019 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9021 sprintf(buf, "%s:\n%s", str, buf2);
\r
9023 ErrorMap *em = errmap;
\r
9024 while (em->err != 0 && em->err != error) em++;
\r
9025 if (em->err != 0) {
\r
9026 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9028 sprintf(buf, "%s:\nError code %d", str, error);
\r
9033 if (appData.debugMode) {
\r
9034 fprintf(debugFP, "%s: %s\n", label, str);
\r
9036 if (appData.popupExitMessage) {
\r
9037 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9038 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9040 ExitEvent(exitStatus);
\r
9045 DisplayInformation(char *str)
\r
9047 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9052 DisplayNote(char *str)
\r
9054 ErrorPopUp("Note", str);
\r
9059 char *title, *question, *replyPrefix;
\r
9064 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9066 static QuestionParams *qp;
\r
9067 char reply[MSG_SIZ];
\r
9070 switch (message) {
\r
9071 case WM_INITDIALOG:
\r
9072 qp = (QuestionParams *) lParam;
\r
9073 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9074 SetWindowText(hDlg, qp->title);
\r
9075 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9076 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9080 switch (LOWORD(wParam)) {
\r
9082 strcpy(reply, qp->replyPrefix);
\r
9083 if (*reply) strcat(reply, " ");
\r
9084 len = strlen(reply);
\r
9085 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9086 strcat(reply, "\n");
\r
9087 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9088 EndDialog(hDlg, TRUE);
\r
9089 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9092 EndDialog(hDlg, FALSE);
\r
9103 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9105 QuestionParams qp;
\r
9109 qp.question = question;
\r
9110 qp.replyPrefix = replyPrefix;
\r
9112 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9113 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9114 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9115 FreeProcInstance(lpProc);
\r
9118 /* [AS] Pick FRC position */
\r
9119 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9121 static int * lpIndexFRC;
\r
9127 case WM_INITDIALOG:
\r
9128 lpIndexFRC = (int *) lParam;
\r
9130 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9132 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9133 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9134 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9135 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9140 switch( LOWORD(wParam) ) {
\r
9142 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9143 EndDialog( hDlg, 0 );
\r
9144 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9147 EndDialog( hDlg, 1 );
\r
9149 case IDC_NFG_Edit:
\r
9150 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9151 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9153 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9156 case IDC_NFG_Random:
\r
9157 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9158 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9171 int index = appData.defaultFrcPosition;
\r
9172 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9174 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9176 if( result == 0 ) {
\r
9177 appData.defaultFrcPosition = index;
\r
9183 /* [AS] Game list options */
\r
9189 static GLT_Item GLT_ItemInfo[] = {
\r
9190 { GLT_EVENT, "Event" },
\r
9191 { GLT_SITE, "Site" },
\r
9192 { GLT_DATE, "Date" },
\r
9193 { GLT_ROUND, "Round" },
\r
9194 { GLT_PLAYERS, "Players" },
\r
9195 { GLT_RESULT, "Result" },
\r
9196 { GLT_WHITE_ELO, "White Rating" },
\r
9197 { GLT_BLACK_ELO, "Black Rating" },
\r
9198 { GLT_TIME_CONTROL,"Time Control" },
\r
9199 { GLT_VARIANT, "Variant" },
\r
9200 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9201 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9205 const char * GLT_FindItem( char id )
\r
9207 const char * result = 0;
\r
9209 GLT_Item * list = GLT_ItemInfo;
\r
9211 while( list->id != 0 ) {
\r
9212 if( list->id == id ) {
\r
9213 result = list->name;
\r
9223 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9225 const char * name = GLT_FindItem( id );
\r
9228 if( index >= 0 ) {
\r
9229 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9232 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9237 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9241 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9244 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9248 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9250 pc = GLT_ALL_TAGS;
\r
9253 if( strchr( tags, *pc ) == 0 ) {
\r
9254 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9259 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9262 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9264 char result = '\0';
\r
9267 GLT_Item * list = GLT_ItemInfo;
\r
9269 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9270 while( list->id != 0 ) {
\r
9271 if( strcmp( list->name, name ) == 0 ) {
\r
9272 result = list->id;
\r
9283 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9285 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9286 int idx2 = idx1 + delta;
\r
9287 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9289 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9292 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9293 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9294 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9295 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9299 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9301 static char glt[64];
\r
9302 static char * lpUserGLT;
\r
9306 case WM_INITDIALOG:
\r
9307 lpUserGLT = (char *) lParam;
\r
9309 strcpy( glt, lpUserGLT );
\r
9311 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9313 /* Initialize list */
\r
9314 GLT_TagsToList( hDlg, glt );
\r
9316 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9321 switch( LOWORD(wParam) ) {
\r
9324 char * pc = lpUserGLT;
\r
9326 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9330 id = GLT_ListItemToTag( hDlg, idx );
\r
9334 } while( id != '\0' );
\r
9336 EndDialog( hDlg, 0 );
\r
9339 EndDialog( hDlg, 1 );
\r
9342 case IDC_GLT_Default:
\r
9343 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9344 GLT_TagsToList( hDlg, glt );
\r
9347 case IDC_GLT_Restore:
\r
9348 strcpy( glt, lpUserGLT );
\r
9349 GLT_TagsToList( hDlg, glt );
\r
9353 GLT_MoveSelection( hDlg, -1 );
\r
9356 case IDC_GLT_Down:
\r
9357 GLT_MoveSelection( hDlg, +1 );
\r
9367 int GameListOptions()
\r
9371 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9373 strcpy( glt, appData.gameListTags );
\r
9375 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9377 if( result == 0 ) {
\r
9378 /* [AS] Memory leak here! */
\r
9379 appData.gameListTags = strdup( glt );
\r
9387 DisplayIcsInteractionTitle(char *str)
\r
9389 char consoleTitle[MSG_SIZ];
\r
9391 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9392 SetWindowText(hwndConsole, consoleTitle);
\r
9396 DrawPosition(int fullRedraw, Board board)
\r
9398 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9401 void NotifyFrontendLogin()
\r
9404 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9410 fromX = fromY = -1;
\r
9411 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9412 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9413 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9414 dragInfo.lastpos = dragInfo.pos;
\r
9415 dragInfo.start.x = dragInfo.start.y = -1;
\r
9416 dragInfo.from = dragInfo.start;
\r
9418 DrawPosition(TRUE, NULL);
\r
9424 CommentPopUp(char *title, char *str)
\r
9426 HWND hwnd = GetActiveWindow();
\r
9427 EitherCommentPopUp(0, title, str, FALSE);
\r
9429 SetActiveWindow(hwnd);
\r
9433 CommentPopDown(void)
\r
9435 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9436 if (commentDialog) {
\r
9437 ShowWindow(commentDialog, SW_HIDE);
\r
9439 commentUp = FALSE;
\r
9443 EditCommentPopUp(int index, char *title, char *str)
\r
9445 EitherCommentPopUp(index, title, str, TRUE);
\r
9452 MyPlaySound(&sounds[(int)SoundMove]);
\r
9455 VOID PlayIcsWinSound()
\r
9457 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9460 VOID PlayIcsLossSound()
\r
9462 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9465 VOID PlayIcsDrawSound()
\r
9467 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9470 VOID PlayIcsUnfinishedSound()
\r
9472 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9478 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9486 consoleEcho = TRUE;
\r
9487 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9488 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9489 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9498 consoleEcho = FALSE;
\r
9499 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9500 /* This works OK: set text and background both to the same color */
\r
9502 cf.crTextColor = COLOR_ECHOOFF;
\r
9503 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9504 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9507 /* No Raw()...? */
\r
9509 void Colorize(ColorClass cc, int continuation)
\r
9511 currentColorClass = cc;
\r
9512 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9513 consoleCF.crTextColor = textAttribs[cc].color;
\r
9514 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9515 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9521 static char buf[MSG_SIZ];
\r
9522 DWORD bufsiz = MSG_SIZ;
\r
9524 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9525 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9527 if (!GetUserName(buf, &bufsiz)) {
\r
9528 /*DisplayError("Error getting user name", GetLastError());*/
\r
9529 strcpy(buf, "User");
\r
9537 static char buf[MSG_SIZ];
\r
9538 DWORD bufsiz = MSG_SIZ;
\r
9540 if (!GetComputerName(buf, &bufsiz)) {
\r
9541 /*DisplayError("Error getting host name", GetLastError());*/
\r
9542 strcpy(buf, "Unknown");
\r
9549 ClockTimerRunning()
\r
9551 return clockTimerEvent != 0;
\r
9557 if (clockTimerEvent == 0) return FALSE;
\r
9558 KillTimer(hwndMain, clockTimerEvent);
\r
9559 clockTimerEvent = 0;
\r
9564 StartClockTimer(long millisec)
\r
9566 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9567 (UINT) millisec, NULL);
\r
9571 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9574 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9576 if(appData.noGUI) return;
\r
9577 hdc = GetDC(hwndMain);
\r
9578 if (!IsIconic(hwndMain)) {
\r
9579 DisplayAClock(hdc, timeRemaining, highlight,
\r
9580 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9582 if (highlight && iconCurrent == iconBlack) {
\r
9583 iconCurrent = iconWhite;
\r
9584 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9585 if (IsIconic(hwndMain)) {
\r
9586 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9589 (void) ReleaseDC(hwndMain, hdc);
\r
9591 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9595 DisplayBlackClock(long timeRemaining, int highlight)
\r
9598 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9600 if(appData.noGUI) return;
\r
9601 hdc = GetDC(hwndMain);
\r
9602 if (!IsIconic(hwndMain)) {
\r
9603 DisplayAClock(hdc, timeRemaining, highlight,
\r
9604 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9606 if (highlight && iconCurrent == iconWhite) {
\r
9607 iconCurrent = iconBlack;
\r
9608 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9609 if (IsIconic(hwndMain)) {
\r
9610 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9613 (void) ReleaseDC(hwndMain, hdc);
\r
9615 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9620 LoadGameTimerRunning()
\r
9622 return loadGameTimerEvent != 0;
\r
9626 StopLoadGameTimer()
\r
9628 if (loadGameTimerEvent == 0) return FALSE;
\r
9629 KillTimer(hwndMain, loadGameTimerEvent);
\r
9630 loadGameTimerEvent = 0;
\r
9635 StartLoadGameTimer(long millisec)
\r
9637 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9638 (UINT) millisec, NULL);
\r
9646 char fileTitle[MSG_SIZ];
\r
9648 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9649 f = OpenFileDialog(hwndMain, "a", defName,
\r
9650 appData.oldSaveStyle ? "gam" : "pgn",
\r
9652 "Save Game to File", NULL, fileTitle, NULL);
\r
9654 SaveGame(f, 0, "");
\r
9661 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9663 if (delayedTimerEvent != 0) {
\r
9664 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9665 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9667 KillTimer(hwndMain, delayedTimerEvent);
\r
9668 delayedTimerEvent = 0;
\r
9669 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9670 delayedTimerCallback();
\r
9672 delayedTimerCallback = cb;
\r
9673 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9674 (UINT) millisec, NULL);
\r
9677 DelayedEventCallback
\r
9680 if (delayedTimerEvent) {
\r
9681 return delayedTimerCallback;
\r
9688 CancelDelayedEvent()
\r
9690 if (delayedTimerEvent) {
\r
9691 KillTimer(hwndMain, delayedTimerEvent);
\r
9692 delayedTimerEvent = 0;
\r
9696 DWORD GetWin32Priority(int nice)
\r
9697 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9699 REALTIME_PRIORITY_CLASS 0x00000100
\r
9700 HIGH_PRIORITY_CLASS 0x00000080
\r
9701 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9702 NORMAL_PRIORITY_CLASS 0x00000020
\r
9703 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9704 IDLE_PRIORITY_CLASS 0x00000040
\r
9706 if (nice < -15) return 0x00000080;
\r
9707 if (nice < 0) return 0x00008000;
\r
9708 if (nice == 0) return 0x00000020;
\r
9709 if (nice < 15) return 0x00004000;
\r
9710 return 0x00000040;
\r
9713 /* Start a child process running the given program.
\r
9714 The process's standard output can be read from "from", and its
\r
9715 standard input can be written to "to".
\r
9716 Exit with fatal error if anything goes wrong.
\r
9717 Returns an opaque pointer that can be used to destroy the process
\r
9721 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9723 #define BUFSIZE 4096
\r
9725 HANDLE hChildStdinRd, hChildStdinWr,
\r
9726 hChildStdoutRd, hChildStdoutWr;
\r
9727 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9728 SECURITY_ATTRIBUTES saAttr;
\r
9730 PROCESS_INFORMATION piProcInfo;
\r
9731 STARTUPINFO siStartInfo;
\r
9733 char buf[MSG_SIZ];
\r
9736 if (appData.debugMode) {
\r
9737 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9742 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9743 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9744 saAttr.bInheritHandle = TRUE;
\r
9745 saAttr.lpSecurityDescriptor = NULL;
\r
9748 * The steps for redirecting child's STDOUT:
\r
9749 * 1. Create anonymous pipe to be STDOUT for child.
\r
9750 * 2. Create a noninheritable duplicate of read handle,
\r
9751 * and close the inheritable read handle.
\r
9754 /* Create a pipe for the child's STDOUT. */
\r
9755 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9756 return GetLastError();
\r
9759 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9760 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9761 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9762 FALSE, /* not inherited */
\r
9763 DUPLICATE_SAME_ACCESS);
\r
9765 return GetLastError();
\r
9767 CloseHandle(hChildStdoutRd);
\r
9770 * The steps for redirecting child's STDIN:
\r
9771 * 1. Create anonymous pipe to be STDIN for child.
\r
9772 * 2. Create a noninheritable duplicate of write handle,
\r
9773 * and close the inheritable write handle.
\r
9776 /* Create a pipe for the child's STDIN. */
\r
9777 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9778 return GetLastError();
\r
9781 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9782 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9783 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9784 FALSE, /* not inherited */
\r
9785 DUPLICATE_SAME_ACCESS);
\r
9787 return GetLastError();
\r
9789 CloseHandle(hChildStdinWr);
\r
9791 /* Arrange to (1) look in dir for the child .exe file, and
\r
9792 * (2) have dir be the child's working directory. Interpret
\r
9793 * dir relative to the directory WinBoard loaded from. */
\r
9794 GetCurrentDirectory(MSG_SIZ, buf);
\r
9795 SetCurrentDirectory(installDir);
\r
9796 SetCurrentDirectory(dir);
\r
9798 /* Now create the child process. */
\r
9800 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9801 siStartInfo.lpReserved = NULL;
\r
9802 siStartInfo.lpDesktop = NULL;
\r
9803 siStartInfo.lpTitle = NULL;
\r
9804 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9805 siStartInfo.cbReserved2 = 0;
\r
9806 siStartInfo.lpReserved2 = NULL;
\r
9807 siStartInfo.hStdInput = hChildStdinRd;
\r
9808 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9809 siStartInfo.hStdError = hChildStdoutWr;
\r
9811 fSuccess = CreateProcess(NULL,
\r
9812 cmdLine, /* command line */
\r
9813 NULL, /* process security attributes */
\r
9814 NULL, /* primary thread security attrs */
\r
9815 TRUE, /* handles are inherited */
\r
9816 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9817 NULL, /* use parent's environment */
\r
9819 &siStartInfo, /* STARTUPINFO pointer */
\r
9820 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9822 err = GetLastError();
\r
9823 SetCurrentDirectory(buf); /* return to prev directory */
\r
9828 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9829 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9830 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9833 /* Close the handles we don't need in the parent */
\r
9834 CloseHandle(piProcInfo.hThread);
\r
9835 CloseHandle(hChildStdinRd);
\r
9836 CloseHandle(hChildStdoutWr);
\r
9838 /* Prepare return value */
\r
9839 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9840 cp->kind = CPReal;
\r
9841 cp->hProcess = piProcInfo.hProcess;
\r
9842 cp->pid = piProcInfo.dwProcessId;
\r
9843 cp->hFrom = hChildStdoutRdDup;
\r
9844 cp->hTo = hChildStdinWrDup;
\r
9846 *pr = (void *) cp;
\r
9848 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9849 2000 where engines sometimes don't see the initial command(s)
\r
9850 from WinBoard and hang. I don't understand how that can happen,
\r
9851 but the Sleep is harmless, so I've put it in. Others have also
\r
9852 reported what may be the same problem, so hopefully this will fix
\r
9853 it for them too. */
\r
9861 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9863 ChildProc *cp; int result;
\r
9865 cp = (ChildProc *) pr;
\r
9866 if (cp == NULL) return;
\r
9868 switch (cp->kind) {
\r
9870 /* TerminateProcess is considered harmful, so... */
\r
9871 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9872 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9873 /* The following doesn't work because the chess program
\r
9874 doesn't "have the same console" as WinBoard. Maybe
\r
9875 we could arrange for this even though neither WinBoard
\r
9876 nor the chess program uses a console for stdio? */
\r
9877 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9879 /* [AS] Special termination modes for misbehaving programs... */
\r
9880 if( signal == 9 ) {
\r
9881 result = TerminateProcess( cp->hProcess, 0 );
\r
9883 if ( appData.debugMode) {
\r
9884 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9887 else if( signal == 10 ) {
\r
9888 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9890 if( dw != WAIT_OBJECT_0 ) {
\r
9891 result = TerminateProcess( cp->hProcess, 0 );
\r
9893 if ( appData.debugMode) {
\r
9894 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9900 CloseHandle(cp->hProcess);
\r
9904 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9908 closesocket(cp->sock);
\r
9913 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9914 closesocket(cp->sock);
\r
9915 closesocket(cp->sock2);
\r
9923 InterruptChildProcess(ProcRef pr)
\r
9927 cp = (ChildProc *) pr;
\r
9928 if (cp == NULL) return;
\r
9929 switch (cp->kind) {
\r
9931 /* The following doesn't work because the chess program
\r
9932 doesn't "have the same console" as WinBoard. Maybe
\r
9933 we could arrange for this even though neither WinBoard
\r
9934 nor the chess program uses a console for stdio */
\r
9935 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9940 /* Can't interrupt */
\r
9944 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9951 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9953 char cmdLine[MSG_SIZ];
\r
9955 if (port[0] == NULLCHAR) {
\r
9956 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9958 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9960 return StartChildProcess(cmdLine, "", pr);
\r
9964 /* Code to open TCP sockets */
\r
9967 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9972 struct sockaddr_in sa, mysa;
\r
9973 struct hostent FAR *hp;
\r
9974 unsigned short uport;
\r
9975 WORD wVersionRequested;
\r
9978 /* Initialize socket DLL */
\r
9979 wVersionRequested = MAKEWORD(1, 1);
\r
9980 err = WSAStartup(wVersionRequested, &wsaData);
\r
9981 if (err != 0) return err;
\r
9984 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9985 err = WSAGetLastError();
\r
9990 /* Bind local address using (mostly) don't-care values.
\r
9992 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9993 mysa.sin_family = AF_INET;
\r
9994 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9995 uport = (unsigned short) 0;
\r
9996 mysa.sin_port = htons(uport);
\r
9997 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9998 == SOCKET_ERROR) {
\r
9999 err = WSAGetLastError();
\r
10004 /* Resolve remote host name */
\r
10005 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10006 if (!(hp = gethostbyname(host))) {
\r
10007 unsigned int b0, b1, b2, b3;
\r
10009 err = WSAGetLastError();
\r
10011 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10012 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10013 hp->h_addrtype = AF_INET;
\r
10014 hp->h_length = 4;
\r
10015 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10016 hp->h_addr_list[0] = (char *) malloc(4);
\r
10017 hp->h_addr_list[0][0] = (char) b0;
\r
10018 hp->h_addr_list[0][1] = (char) b1;
\r
10019 hp->h_addr_list[0][2] = (char) b2;
\r
10020 hp->h_addr_list[0][3] = (char) b3;
\r
10026 sa.sin_family = hp->h_addrtype;
\r
10027 uport = (unsigned short) atoi(port);
\r
10028 sa.sin_port = htons(uport);
\r
10029 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10031 /* Make connection */
\r
10032 if (connect(s, (struct sockaddr *) &sa,
\r
10033 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10034 err = WSAGetLastError();
\r
10039 /* Prepare return value */
\r
10040 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10041 cp->kind = CPSock;
\r
10043 *pr = (ProcRef *) cp;
\r
10049 OpenCommPort(char *name, ProcRef *pr)
\r
10054 char fullname[MSG_SIZ];
\r
10056 if (*name != '\\')
\r
10057 sprintf(fullname, "\\\\.\\%s", name);
\r
10059 strcpy(fullname, name);
\r
10061 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10062 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10063 if (h == (HANDLE) -1) {
\r
10064 return GetLastError();
\r
10068 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10070 /* Accumulate characters until a 100ms pause, then parse */
\r
10071 ct.ReadIntervalTimeout = 100;
\r
10072 ct.ReadTotalTimeoutMultiplier = 0;
\r
10073 ct.ReadTotalTimeoutConstant = 0;
\r
10074 ct.WriteTotalTimeoutMultiplier = 0;
\r
10075 ct.WriteTotalTimeoutConstant = 0;
\r
10076 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10078 /* Prepare return value */
\r
10079 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10080 cp->kind = CPComm;
\r
10083 *pr = (ProcRef *) cp;
\r
10089 OpenLoopback(ProcRef *pr)
\r
10091 DisplayFatalError("Not implemented", 0, 1);
\r
10097 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10101 SOCKET s, s2, s3;
\r
10102 struct sockaddr_in sa, mysa;
\r
10103 struct hostent FAR *hp;
\r
10104 unsigned short uport;
\r
10105 WORD wVersionRequested;
\r
10108 char stderrPortStr[MSG_SIZ];
\r
10110 /* Initialize socket DLL */
\r
10111 wVersionRequested = MAKEWORD(1, 1);
\r
10112 err = WSAStartup(wVersionRequested, &wsaData);
\r
10113 if (err != 0) return err;
\r
10115 /* Resolve remote host name */
\r
10116 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10117 if (!(hp = gethostbyname(host))) {
\r
10118 unsigned int b0, b1, b2, b3;
\r
10120 err = WSAGetLastError();
\r
10122 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10123 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10124 hp->h_addrtype = AF_INET;
\r
10125 hp->h_length = 4;
\r
10126 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10127 hp->h_addr_list[0] = (char *) malloc(4);
\r
10128 hp->h_addr_list[0][0] = (char) b0;
\r
10129 hp->h_addr_list[0][1] = (char) b1;
\r
10130 hp->h_addr_list[0][2] = (char) b2;
\r
10131 hp->h_addr_list[0][3] = (char) b3;
\r
10137 sa.sin_family = hp->h_addrtype;
\r
10138 uport = (unsigned short) 514;
\r
10139 sa.sin_port = htons(uport);
\r
10140 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10142 /* Bind local socket to unused "privileged" port address
\r
10144 s = INVALID_SOCKET;
\r
10145 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10146 mysa.sin_family = AF_INET;
\r
10147 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10148 for (fromPort = 1023;; fromPort--) {
\r
10149 if (fromPort < 0) {
\r
10151 return WSAEADDRINUSE;
\r
10153 if (s == INVALID_SOCKET) {
\r
10154 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10155 err = WSAGetLastError();
\r
10160 uport = (unsigned short) fromPort;
\r
10161 mysa.sin_port = htons(uport);
\r
10162 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10163 == SOCKET_ERROR) {
\r
10164 err = WSAGetLastError();
\r
10165 if (err == WSAEADDRINUSE) continue;
\r
10169 if (connect(s, (struct sockaddr *) &sa,
\r
10170 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10171 err = WSAGetLastError();
\r
10172 if (err == WSAEADDRINUSE) {
\r
10183 /* Bind stderr local socket to unused "privileged" port address
\r
10185 s2 = INVALID_SOCKET;
\r
10186 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10187 mysa.sin_family = AF_INET;
\r
10188 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10189 for (fromPort = 1023;; fromPort--) {
\r
10190 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10191 if (fromPort < 0) {
\r
10192 (void) closesocket(s);
\r
10194 return WSAEADDRINUSE;
\r
10196 if (s2 == INVALID_SOCKET) {
\r
10197 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10198 err = WSAGetLastError();
\r
10204 uport = (unsigned short) fromPort;
\r
10205 mysa.sin_port = htons(uport);
\r
10206 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10207 == SOCKET_ERROR) {
\r
10208 err = WSAGetLastError();
\r
10209 if (err == WSAEADDRINUSE) continue;
\r
10210 (void) closesocket(s);
\r
10214 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10215 err = WSAGetLastError();
\r
10216 if (err == WSAEADDRINUSE) {
\r
10218 s2 = INVALID_SOCKET;
\r
10221 (void) closesocket(s);
\r
10222 (void) closesocket(s2);
\r
10228 prevStderrPort = fromPort; // remember port used
\r
10229 sprintf(stderrPortStr, "%d", fromPort);
\r
10231 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10232 err = WSAGetLastError();
\r
10233 (void) closesocket(s);
\r
10234 (void) closesocket(s2);
\r
10239 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10240 err = WSAGetLastError();
\r
10241 (void) closesocket(s);
\r
10242 (void) closesocket(s2);
\r
10246 if (*user == NULLCHAR) user = UserName();
\r
10247 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10248 err = WSAGetLastError();
\r
10249 (void) closesocket(s);
\r
10250 (void) closesocket(s2);
\r
10254 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10255 err = WSAGetLastError();
\r
10256 (void) closesocket(s);
\r
10257 (void) closesocket(s2);
\r
10262 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10263 err = WSAGetLastError();
\r
10264 (void) closesocket(s);
\r
10265 (void) closesocket(s2);
\r
10269 (void) closesocket(s2); /* Stop listening */
\r
10271 /* Prepare return value */
\r
10272 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10273 cp->kind = CPRcmd;
\r
10276 *pr = (ProcRef *) cp;
\r
10283 AddInputSource(ProcRef pr, int lineByLine,
\r
10284 InputCallback func, VOIDSTAR closure)
\r
10286 InputSource *is, *is2 = NULL;
\r
10287 ChildProc *cp = (ChildProc *) pr;
\r
10289 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10290 is->lineByLine = lineByLine;
\r
10292 is->closure = closure;
\r
10293 is->second = NULL;
\r
10294 is->next = is->buf;
\r
10295 if (pr == NoProc) {
\r
10296 is->kind = CPReal;
\r
10297 consoleInputSource = is;
\r
10299 is->kind = cp->kind;
\r
10301 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10302 we create all threads suspended so that the is->hThread variable can be
\r
10303 safely assigned, then let the threads start with ResumeThread.
\r
10305 switch (cp->kind) {
\r
10307 is->hFile = cp->hFrom;
\r
10308 cp->hFrom = NULL; /* now owned by InputThread */
\r
10310 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10311 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10315 is->hFile = cp->hFrom;
\r
10316 cp->hFrom = NULL; /* now owned by InputThread */
\r
10318 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10319 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10323 is->sock = cp->sock;
\r
10325 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10326 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10330 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10332 is->sock = cp->sock;
\r
10333 is->second = is2;
\r
10334 is2->sock = cp->sock2;
\r
10335 is2->second = is2;
\r
10337 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10338 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10340 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10341 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10345 if( is->hThread != NULL ) {
\r
10346 ResumeThread( is->hThread );
\r
10349 if( is2 != NULL && is2->hThread != NULL ) {
\r
10350 ResumeThread( is2->hThread );
\r
10354 return (InputSourceRef) is;
\r
10358 RemoveInputSource(InputSourceRef isr)
\r
10362 is = (InputSource *) isr;
\r
10363 is->hThread = NULL; /* tell thread to stop */
\r
10364 CloseHandle(is->hThread);
\r
10365 if (is->second != NULL) {
\r
10366 is->second->hThread = NULL;
\r
10367 CloseHandle(is->second->hThread);
\r
10371 int no_wrap(char *message, int count)
\r
10373 ConsoleOutput(message, count, FALSE);
\r
10378 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10381 int outCount = SOCKET_ERROR;
\r
10382 ChildProc *cp = (ChildProc *) pr;
\r
10383 static OVERLAPPED ovl;
\r
10384 static int line = 0;
\r
10386 if (pr == NoProc)
\r
10388 if (appData.noJoin || !appData.useInternalWrap)
\r
10389 return no_wrap(message, count);
\r
10392 int width = get_term_width();
\r
10393 int len = wrap(NULL, message, count, width, &line);
\r
10394 char *msg = malloc(len);
\r
10398 return no_wrap(message, count);
\r
10401 dbgchk = wrap(msg, message, count, width, &line);
\r
10402 if (dbgchk != len && appData.debugMode)
\r
10403 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10404 ConsoleOutput(msg, len, FALSE);
\r
10411 if (ovl.hEvent == NULL) {
\r
10412 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10414 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10416 switch (cp->kind) {
\r
10419 outCount = send(cp->sock, message, count, 0);
\r
10420 if (outCount == SOCKET_ERROR) {
\r
10421 *outError = WSAGetLastError();
\r
10423 *outError = NO_ERROR;
\r
10428 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10429 &dOutCount, NULL)) {
\r
10430 *outError = NO_ERROR;
\r
10431 outCount = (int) dOutCount;
\r
10433 *outError = GetLastError();
\r
10438 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10439 &dOutCount, &ovl);
\r
10440 if (*outError == NO_ERROR) {
\r
10441 outCount = (int) dOutCount;
\r
10449 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10452 /* Ignore delay, not implemented for WinBoard */
\r
10453 return OutputToProcess(pr, message, count, outError);
\r
10458 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10459 char *buf, int count, int error)
\r
10461 DisplayFatalError("Not implemented", 0, 1);
\r
10464 /* see wgamelist.c for Game List functions */
\r
10465 /* see wedittags.c for Edit Tags functions */
\r
10472 char buf[MSG_SIZ];
\r
10475 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10476 f = fopen(buf, "r");
\r
10478 ProcessICSInitScript(f);
\r
10486 StartAnalysisClock()
\r
10488 if (analysisTimerEvent) return;
\r
10489 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10490 (UINT) 2000, NULL);
\r
10494 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10496 static HANDLE hwndText;
\r
10498 static int sizeX, sizeY;
\r
10499 int newSizeX, newSizeY, flags;
\r
10502 switch (message) {
\r
10503 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10504 /* Initialize the dialog items */
\r
10505 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10506 SetWindowText(hDlg, analysisTitle);
\r
10507 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10508 /* Size and position the dialog */
\r
10509 if (!analysisDialog) {
\r
10510 analysisDialog = hDlg;
\r
10511 flags = SWP_NOZORDER;
\r
10512 GetClientRect(hDlg, &rect);
\r
10513 sizeX = rect.right;
\r
10514 sizeY = rect.bottom;
\r
10515 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10516 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10517 WINDOWPLACEMENT wp;
\r
10518 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10519 wp.length = sizeof(WINDOWPLACEMENT);
\r
10521 wp.showCmd = SW_SHOW;
\r
10522 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10523 wp.rcNormalPosition.left = analysisX;
\r
10524 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10525 wp.rcNormalPosition.top = analysisY;
\r
10526 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10527 SetWindowPlacement(hDlg, &wp);
\r
10529 GetClientRect(hDlg, &rect);
\r
10530 newSizeX = rect.right;
\r
10531 newSizeY = rect.bottom;
\r
10532 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10533 newSizeX, newSizeY);
\r
10534 sizeX = newSizeX;
\r
10535 sizeY = newSizeY;
\r
10540 case WM_COMMAND: /* message: received a command */
\r
10541 switch (LOWORD(wParam)) {
\r
10543 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10544 ExitAnalyzeMode();
\r
10556 newSizeX = LOWORD(lParam);
\r
10557 newSizeY = HIWORD(lParam);
\r
10558 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10559 sizeX = newSizeX;
\r
10560 sizeY = newSizeY;
\r
10563 case WM_GETMINMAXINFO:
\r
10564 /* Prevent resizing window too small */
\r
10565 mmi = (MINMAXINFO *) lParam;
\r
10566 mmi->ptMinTrackSize.x = 100;
\r
10567 mmi->ptMinTrackSize.y = 100;
\r
10574 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10576 highlightInfo.sq[0].x = fromX;
\r
10577 highlightInfo.sq[0].y = fromY;
\r
10578 highlightInfo.sq[1].x = toX;
\r
10579 highlightInfo.sq[1].y = toY;
\r
10583 ClearHighlights()
\r
10585 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10586 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10590 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10592 premoveHighlightInfo.sq[0].x = fromX;
\r
10593 premoveHighlightInfo.sq[0].y = fromY;
\r
10594 premoveHighlightInfo.sq[1].x = toX;
\r
10595 premoveHighlightInfo.sq[1].y = toY;
\r
10599 ClearPremoveHighlights()
\r
10601 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10602 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10606 ShutDownFrontEnd()
\r
10608 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10609 DeleteClipboardTempFiles();
\r
10615 if (IsIconic(hwndMain))
\r
10616 ShowWindow(hwndMain, SW_RESTORE);
\r
10618 SetActiveWindow(hwndMain);
\r
10622 * Prototypes for animation support routines
\r
10624 static void ScreenSquare(int column, int row, POINT * pt);
\r
10625 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10626 POINT frames[], int * nFrames);
\r
10630 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10631 { // [HGM] atomic: animate blast wave
\r
10633 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10634 explodeInfo.fromX = fromX;
\r
10635 explodeInfo.fromY = fromY;
\r
10636 explodeInfo.toX = toX;
\r
10637 explodeInfo.toY = toY;
\r
10638 for(i=1; i<nFrames; i++) {
\r
10639 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10640 DrawPosition(FALSE, NULL);
\r
10641 Sleep(appData.animSpeed);
\r
10643 explodeInfo.radius = 0;
\r
10644 DrawPosition(TRUE, NULL);
\r
10647 #define kFactor 4
\r
10650 AnimateMove(board, fromX, fromY, toX, toY)
\r
10657 ChessSquare piece;
\r
10658 POINT start, finish, mid;
\r
10659 POINT frames[kFactor * 2 + 1];
\r
10662 if (!appData.animate) return;
\r
10663 if (doingSizing) return;
\r
10664 if (fromY < 0 || fromX < 0) return;
\r
10665 piece = board[fromY][fromX];
\r
10666 if (piece >= EmptySquare) return;
\r
10668 ScreenSquare(fromX, fromY, &start);
\r
10669 ScreenSquare(toX, toY, &finish);
\r
10671 /* All pieces except knights move in straight line */
\r
10672 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10673 mid.x = start.x + (finish.x - start.x) / 2;
\r
10674 mid.y = start.y + (finish.y - start.y) / 2;
\r
10676 /* Knight: make diagonal movement then straight */
\r
10677 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10678 mid.x = start.x + (finish.x - start.x) / 2;
\r
10679 mid.y = finish.y;
\r
10681 mid.x = finish.x;
\r
10682 mid.y = start.y + (finish.y - start.y) / 2;
\r
10686 /* Don't use as many frames for very short moves */
\r
10687 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10688 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10690 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10692 animInfo.from.x = fromX;
\r
10693 animInfo.from.y = fromY;
\r
10694 animInfo.to.x = toX;
\r
10695 animInfo.to.y = toY;
\r
10696 animInfo.lastpos = start;
\r
10697 animInfo.piece = piece;
\r
10698 for (n = 0; n < nFrames; n++) {
\r
10699 animInfo.pos = frames[n];
\r
10700 DrawPosition(FALSE, NULL);
\r
10701 animInfo.lastpos = animInfo.pos;
\r
10702 Sleep(appData.animSpeed);
\r
10704 animInfo.pos = finish;
\r
10705 DrawPosition(FALSE, NULL);
\r
10706 animInfo.piece = EmptySquare;
\r
10707 if(gameInfo.variant == VariantAtomic &&
\r
10708 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10709 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10712 /* Convert board position to corner of screen rect and color */
\r
10715 ScreenSquare(column, row, pt)
\r
10716 int column; int row; POINT * pt;
\r
10719 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10720 pt->y = lineGap + row * (squareSize + lineGap);
\r
10722 pt->x = lineGap + column * (squareSize + lineGap);
\r
10723 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10727 /* Generate a series of frame coords from start->mid->finish.
\r
10728 The movement rate doubles until the half way point is
\r
10729 reached, then halves back down to the final destination,
\r
10730 which gives a nice slow in/out effect. The algorithmn
\r
10731 may seem to generate too many intermediates for short
\r
10732 moves, but remember that the purpose is to attract the
\r
10733 viewers attention to the piece about to be moved and
\r
10734 then to where it ends up. Too few frames would be less
\r
10738 Tween(start, mid, finish, factor, frames, nFrames)
\r
10739 POINT * start; POINT * mid;
\r
10740 POINT * finish; int factor;
\r
10741 POINT frames[]; int * nFrames;
\r
10743 int n, fraction = 1, count = 0;
\r
10745 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10746 for (n = 0; n < factor; n++)
\r
10748 for (n = 0; n < factor; n++) {
\r
10749 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10750 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10752 fraction = fraction / 2;
\r
10756 frames[count] = *mid;
\r
10759 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10761 for (n = 0; n < factor; n++) {
\r
10762 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10763 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10765 fraction = fraction * 2;
\r
10767 *nFrames = count;
\r
10771 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10773 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10775 EvalGraphSet( first, last, current, pvInfoList );
\r
10778 void SetProgramStats( FrontEndProgramStats * stats )
\r
10780 EngineOutputUpdate( stats );
\r