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
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
291 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
292 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
293 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
294 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 BOOLEAN commentDialogUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 BOOLEAN engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1109 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1110 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1112 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1113 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1114 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1115 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1116 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1117 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1118 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1119 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1120 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1121 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1122 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1123 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1124 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1125 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1126 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1127 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1128 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1129 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1130 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1131 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1132 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1133 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1134 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1135 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1136 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1137 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1138 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1139 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1140 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1141 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1142 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1143 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1144 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1145 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1146 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1147 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1148 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1149 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1150 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1151 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1152 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1153 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1154 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1155 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1156 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1157 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1158 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1159 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1160 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1161 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1162 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1163 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1164 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1165 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1166 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1167 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1168 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1169 { "highlightLastMove", ArgBoolean,
\r
1170 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1171 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1172 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1173 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1174 { "highlightDragging", ArgBoolean,
\r
1175 (LPVOID) &appData.highlightDragging, TRUE },
\r
1176 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1177 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1178 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1179 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1180 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1181 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1182 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1183 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1184 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1185 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1186 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1187 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1188 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1189 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1190 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1191 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1192 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1193 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1194 { "soundShout", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1196 { "soundSShout", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1198 { "soundChannel1", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1200 { "soundChannel", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1202 { "soundKibitz", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1204 { "soundTell", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1206 { "soundChallenge", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1208 { "soundRequest", ArgFilename,
\r
1209 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1210 { "soundSeek", ArgFilename,
\r
1211 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1212 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1213 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1214 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1215 { "soundIcsLoss", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1217 { "soundIcsDraw", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1219 { "soundIcsUnfinished", ArgFilename,
\r
1220 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1221 { "soundIcsAlarm", ArgFilename,
\r
1222 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1223 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1224 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1225 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1226 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1227 { "reuseChessPrograms", ArgBoolean,
\r
1228 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1229 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1230 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1231 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1232 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1233 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1234 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1235 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1236 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1237 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1238 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1239 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1240 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1241 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1242 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1243 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1245 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1247 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1248 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1249 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1250 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1251 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1252 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1253 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1254 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1255 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1256 /* [AS] New features */
\r
1257 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1258 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1259 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1260 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1261 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1262 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1263 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1264 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1265 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1266 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1267 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1268 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1269 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1270 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1271 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1272 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1273 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1274 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1275 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1276 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1277 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1278 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1279 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1280 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1281 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1282 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1283 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1284 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1285 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1286 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1287 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1288 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1289 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1290 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1291 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1292 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1293 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1294 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1295 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1296 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1297 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1298 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1299 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1300 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1301 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1302 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1303 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1304 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1305 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1306 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1308 /* [HGM] board-size, adjudication and misc. options */
\r
1309 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1310 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1311 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1312 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1313 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1314 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1315 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1316 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1317 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1318 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1319 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1320 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1321 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1322 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1323 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1324 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1325 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1326 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1327 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1328 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1329 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1330 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1331 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1332 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1333 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1334 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1335 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1336 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1337 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1338 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1339 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1340 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1341 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1342 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1345 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1346 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1347 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1348 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1349 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1350 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1351 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1352 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1353 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1354 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1355 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1356 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1357 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1359 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1360 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1361 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1362 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1363 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1364 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1365 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1367 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1368 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1369 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1370 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1371 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1372 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1373 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1374 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1375 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1376 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1377 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1378 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1379 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1380 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1381 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1382 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1383 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1384 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1385 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1387 /* [HGM] options for broadcasting and time odds */
\r
1388 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1389 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1390 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1391 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1392 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1393 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1394 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1395 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1396 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1397 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1398 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1400 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1401 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1402 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1403 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1404 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1405 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1406 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1407 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1408 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1409 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1410 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1411 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1412 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1413 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1414 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1415 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1416 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1417 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1418 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1419 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1420 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1421 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1422 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1423 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1424 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1425 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1426 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1427 /* [AS] Layout stuff */
\r
1428 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1429 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1430 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1431 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1432 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1434 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1435 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1436 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1437 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1438 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1440 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1441 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1442 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1443 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1444 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1446 { NULL, ArgNone, NULL, FALSE }
\r
1450 /* Kludge for indirection files on command line */
\r
1451 char* lastIndirectionFilename;
\r
1452 ArgDescriptor argDescriptorIndirection =
\r
1453 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1457 ExitArgError(char *msg, char *badArg)
\r
1459 char buf[MSG_SIZ];
\r
1461 sprintf(buf, "%s %s", msg, badArg);
\r
1462 DisplayFatalError(buf, 0, 2);
\r
1466 /* Command line font name parser. NULL name means do nothing.
\r
1467 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1468 For backward compatibility, syntax without the colon is also
\r
1469 accepted, but font names with digits in them won't work in that case.
\r
1472 ParseFontName(char *name, MyFontParams *mfp)
\r
1475 if (name == NULL) return;
\r
1477 q = strchr(p, ':');
\r
1479 if (q - p >= sizeof(mfp->faceName))
\r
1480 ExitArgError("Font name too long:", name);
\r
1481 memcpy(mfp->faceName, p, q - p);
\r
1482 mfp->faceName[q - p] = NULLCHAR;
\r
1485 q = mfp->faceName;
\r
1486 while (*p && !isdigit(*p)) {
\r
1488 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1489 ExitArgError("Font name too long:", name);
\r
1491 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1494 if (!*p) ExitArgError("Font point size missing:", name);
\r
1495 mfp->pointSize = (float) atof(p);
\r
1496 mfp->bold = (strchr(p, 'b') != NULL);
\r
1497 mfp->italic = (strchr(p, 'i') != NULL);
\r
1498 mfp->underline = (strchr(p, 'u') != NULL);
\r
1499 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1502 /* Color name parser.
\r
1503 X version accepts X color names, but this one
\r
1504 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1506 ParseColorName(char *name)
\r
1508 int red, green, blue, count;
\r
1509 char buf[MSG_SIZ];
\r
1511 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1513 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1514 &red, &green, &blue);
\r
1517 sprintf(buf, "Can't parse color name %s", name);
\r
1518 DisplayError(buf, 0);
\r
1519 return RGB(0, 0, 0);
\r
1521 return PALETTERGB(red, green, blue);
\r
1525 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1527 char *e = argValue;
\r
1531 if (*e == 'b') eff |= CFE_BOLD;
\r
1532 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1533 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1534 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1535 else if (*e == '#' || isdigit(*e)) break;
\r
1539 *color = ParseColorName(e);
\r
1544 ParseBoardSize(char *name)
\r
1546 BoardSize bs = SizeTiny;
\r
1547 while (sizeInfo[bs].name != NULL) {
\r
1548 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1551 ExitArgError("Unrecognized board size value", name);
\r
1552 return bs; /* not reached */
\r
1557 StringGet(void *getClosure)
\r
1559 char **p = (char **) getClosure;
\r
1564 FileGet(void *getClosure)
\r
1567 FILE* f = (FILE*) getClosure;
\r
1570 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1577 /* Parse settings file named "name". If file found, return the
\r
1578 full name in fullname and return TRUE; else return FALSE */
\r
1580 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1584 int ok; char buf[MSG_SIZ];
\r
1586 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1587 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1588 sprintf(buf, "%s.ini", name);
\r
1589 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1592 f = fopen(fullname, "r");
\r
1594 ParseArgs(FileGet, f);
\r
1603 ParseArgs(GetFunc get, void *cl)
\r
1605 char argName[ARG_MAX];
\r
1606 char argValue[ARG_MAX];
\r
1607 ArgDescriptor *ad;
\r
1616 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1617 if (ch == NULLCHAR) break;
\r
1619 /* Comment to end of line */
\r
1621 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1623 } else if (ch == '/' || ch == '-') {
\r
1626 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1627 ch != '\n' && ch != '\t') {
\r
1633 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1634 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1636 if (ad->argName == NULL)
\r
1637 ExitArgError("Unrecognized argument", argName);
\r
1639 } else if (ch == '@') {
\r
1640 /* Indirection file */
\r
1641 ad = &argDescriptorIndirection;
\r
1644 /* Positional argument */
\r
1645 ad = &argDescriptors[posarg++];
\r
1646 strcpy(argName, ad->argName);
\r
1649 if (ad->argType == ArgTrue) {
\r
1650 *(Boolean *) ad->argLoc = TRUE;
\r
1653 if (ad->argType == ArgFalse) {
\r
1654 *(Boolean *) ad->argLoc = FALSE;
\r
1658 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1659 if (ch == NULLCHAR || ch == '\n') {
\r
1660 ExitArgError("No value provided for argument", argName);
\r
1664 // Quoting with { }. No characters have to (or can) be escaped.
\r
1665 // Thus the string cannot contain a '}' character.
\r
1685 } else if (ch == '\'' || ch == '"') {
\r
1686 // Quoting with ' ' or " ", with \ as escape character.
\r
1687 // Inconvenient for long strings that may contain Windows filenames.
\r
1704 if (ch == start) {
\r
1713 if (ad->argType == ArgFilename
\r
1714 || ad->argType == ArgSettingsFilename) {
\r
1720 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1744 for (i = 0; i < 3; i++) {
\r
1745 if (ch >= '0' && ch <= '7') {
\r
1746 octval = octval*8 + (ch - '0');
\r
1753 *q++ = (char) octval;
\r
1764 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1771 switch (ad->argType) {
\r
1773 *(int *) ad->argLoc = atoi(argValue);
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1781 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1785 *(int *) ad->argLoc = atoi(argValue);
\r
1786 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1790 *(float *) ad->argLoc = (float) atof(argValue);
\r
1795 *(char **) ad->argLoc = strdup(argValue);
\r
1798 case ArgSettingsFilename:
\r
1800 char fullname[MSG_SIZ];
\r
1801 if (ParseSettingsFile(argValue, fullname)) {
\r
1802 if (ad->argLoc != NULL) {
\r
1803 *(char **) ad->argLoc = strdup(fullname);
\r
1806 if (ad->argLoc != NULL) {
\r
1808 ExitArgError("Failed to open indirection file", argValue);
\r
1815 switch (argValue[0]) {
\r
1818 *(Boolean *) ad->argLoc = TRUE;
\r
1822 *(Boolean *) ad->argLoc = FALSE;
\r
1825 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1831 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1834 case ArgAttribs: {
\r
1835 ColorClass cc = (ColorClass)ad->argLoc;
\r
1836 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1840 case ArgBoardSize:
\r
1841 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1845 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1848 case ArgCommSettings:
\r
1849 ParseCommSettings(argValue, &dcb);
\r
1853 ExitArgError("Unrecognized argument", argValue);
\r
1862 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1864 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1865 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1868 lf->lfEscapement = 0;
\r
1869 lf->lfOrientation = 0;
\r
1870 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1871 lf->lfItalic = mfp->italic;
\r
1872 lf->lfUnderline = mfp->underline;
\r
1873 lf->lfStrikeOut = mfp->strikeout;
\r
1874 lf->lfCharSet = DEFAULT_CHARSET;
\r
1875 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1876 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1877 lf->lfQuality = DEFAULT_QUALITY;
\r
1878 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1879 strcpy(lf->lfFaceName, mfp->faceName);
\r
1883 CreateFontInMF(MyFont *mf)
\r
1885 LFfromMFP(&mf->lf, &mf->mfp);
\r
1886 if (mf->hf) DeleteObject(mf->hf);
\r
1887 mf->hf = CreateFontIndirect(&mf->lf);
\r
1891 SetDefaultTextAttribs()
\r
1894 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1895 ParseAttribs(&textAttribs[cc].color,
\r
1896 &textAttribs[cc].effects,
\r
1897 defaultTextAttribs[cc]);
\r
1902 SetDefaultSounds()
\r
1906 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1907 textAttribs[cc].sound.name = strdup("");
\r
1908 textAttribs[cc].sound.data = NULL;
\r
1910 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1911 sounds[sc].name = strdup("");
\r
1912 sounds[sc].data = NULL;
\r
1914 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1922 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1923 MyLoadSound(&textAttribs[cc].sound);
\r
1925 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1926 MyLoadSound(&sounds[sc]);
\r
1931 InitAppData(LPSTR lpCmdLine)
\r
1934 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1937 programName = szAppName;
\r
1939 /* Initialize to defaults */
\r
1940 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1941 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1942 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1943 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1944 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1945 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1946 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1947 SetDefaultTextAttribs();
\r
1948 SetDefaultSounds();
\r
1949 appData.movesPerSession = MOVES_PER_SESSION;
\r
1950 appData.initString = INIT_STRING;
\r
1951 appData.secondInitString = INIT_STRING;
\r
1952 appData.firstComputerString = COMPUTER_STRING;
\r
1953 appData.secondComputerString = COMPUTER_STRING;
\r
1954 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1955 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1956 appData.firstPlaysBlack = FALSE;
\r
1957 appData.noChessProgram = FALSE;
\r
1958 chessProgram = FALSE;
\r
1959 appData.firstHost = FIRST_HOST;
\r
1960 appData.secondHost = SECOND_HOST;
\r
1961 appData.firstDirectory = FIRST_DIRECTORY;
\r
1962 appData.secondDirectory = SECOND_DIRECTORY;
\r
1963 appData.bitmapDirectory = "";
\r
1964 appData.remoteShell = REMOTE_SHELL;
\r
1965 appData.remoteUser = "";
\r
1966 appData.timeDelay = TIME_DELAY;
\r
1967 appData.timeControl = TIME_CONTROL;
\r
1968 appData.timeIncrement = TIME_INCREMENT;
\r
1969 appData.icsActive = FALSE;
\r
1970 appData.icsHost = "";
\r
1971 appData.icsPort = ICS_PORT;
\r
1972 appData.icsCommPort = ICS_COMM_PORT;
\r
1973 appData.icsLogon = ICS_LOGON;
\r
1974 appData.icsHelper = "";
\r
1975 appData.useTelnet = FALSE;
\r
1976 appData.telnetProgram = TELNET_PROGRAM;
\r
1977 appData.gateway = "";
\r
1978 appData.loadGameFile = "";
\r
1979 appData.loadGameIndex = 0;
\r
1980 appData.saveGameFile = "";
\r
1981 appData.autoSaveGames = FALSE;
\r
1982 appData.loadPositionFile = "";
\r
1983 appData.loadPositionIndex = 1;
\r
1984 appData.savePositionFile = "";
\r
1985 appData.matchMode = FALSE;
\r
1986 appData.matchGames = 0;
\r
1987 appData.monoMode = FALSE;
\r
1988 appData.debugMode = FALSE;
\r
1989 appData.clockMode = TRUE;
\r
1990 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1991 appData.Iconic = FALSE; /*unused*/
\r
1992 appData.searchTime = "";
\r
1993 appData.searchDepth = 0;
\r
1994 appData.showCoords = FALSE;
\r
1995 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1996 appData.autoCallFlag = FALSE;
\r
1997 appData.flipView = FALSE;
\r
1998 appData.autoFlipView = TRUE;
\r
1999 appData.cmailGameName = "";
\r
2000 appData.alwaysPromoteToQueen = FALSE;
\r
2001 appData.oldSaveStyle = FALSE;
\r
2002 appData.quietPlay = FALSE;
\r
2003 appData.showThinking = FALSE;
\r
2004 appData.ponderNextMove = TRUE;
\r
2005 appData.periodicUpdates = TRUE;
\r
2006 appData.popupExitMessage = TRUE;
\r
2007 appData.popupMoveErrors = FALSE;
\r
2008 appData.autoObserve = FALSE;
\r
2009 appData.autoComment = FALSE;
\r
2010 appData.animate = TRUE;
\r
2011 appData.animSpeed = 10;
\r
2012 appData.animateDragging = TRUE;
\r
2013 appData.highlightLastMove = TRUE;
\r
2014 appData.getMoveList = TRUE;
\r
2015 appData.testLegality = TRUE;
\r
2016 appData.premove = TRUE;
\r
2017 appData.premoveWhite = FALSE;
\r
2018 appData.premoveWhiteText = "";
\r
2019 appData.premoveBlack = FALSE;
\r
2020 appData.premoveBlackText = "";
\r
2021 appData.icsAlarm = TRUE;
\r
2022 appData.icsAlarmTime = 5000;
\r
2023 appData.autoRaiseBoard = TRUE;
\r
2024 appData.localLineEditing = TRUE;
\r
2025 appData.colorize = TRUE;
\r
2026 appData.reuseFirst = TRUE;
\r
2027 appData.reuseSecond = TRUE;
\r
2028 appData.blindfold = FALSE;
\r
2029 appData.icsEngineAnalyze = FALSE;
\r
2030 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2031 dcb.DCBlength = sizeof(DCB);
\r
2032 dcb.BaudRate = 9600;
\r
2033 dcb.fBinary = TRUE;
\r
2034 dcb.fParity = FALSE;
\r
2035 dcb.fOutxCtsFlow = FALSE;
\r
2036 dcb.fOutxDsrFlow = FALSE;
\r
2037 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2038 dcb.fDsrSensitivity = FALSE;
\r
2039 dcb.fTXContinueOnXoff = TRUE;
\r
2040 dcb.fOutX = FALSE;
\r
2042 dcb.fNull = FALSE;
\r
2043 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2044 dcb.fAbortOnError = FALSE;
\r
2046 dcb.Parity = SPACEPARITY;
\r
2047 dcb.StopBits = ONESTOPBIT;
\r
2048 settingsFileName = SETTINGS_FILE;
\r
2049 saveSettingsOnExit = TRUE;
\r
2050 boardX = CW_USEDEFAULT;
\r
2051 boardY = CW_USEDEFAULT;
\r
2052 analysisX = CW_USEDEFAULT;
\r
2053 analysisY = CW_USEDEFAULT;
\r
2054 analysisW = CW_USEDEFAULT;
\r
2055 analysisH = CW_USEDEFAULT;
\r
2056 commentX = CW_USEDEFAULT;
\r
2057 commentY = CW_USEDEFAULT;
\r
2058 commentW = CW_USEDEFAULT;
\r
2059 commentH = CW_USEDEFAULT;
\r
2060 editTagsX = CW_USEDEFAULT;
\r
2061 editTagsY = CW_USEDEFAULT;
\r
2062 editTagsW = CW_USEDEFAULT;
\r
2063 editTagsH = CW_USEDEFAULT;
\r
2064 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2065 icsNames = ICS_NAMES;
\r
2066 firstChessProgramNames = FCP_NAMES;
\r
2067 secondChessProgramNames = SCP_NAMES;
\r
2068 appData.initialMode = "";
\r
2069 appData.variant = "normal";
\r
2070 appData.firstProtocolVersion = PROTOVER;
\r
2071 appData.secondProtocolVersion = PROTOVER;
\r
2072 appData.showButtonBar = TRUE;
\r
2074 /* [AS] New properties (see comments in header file) */
\r
2075 appData.firstScoreIsAbsolute = FALSE;
\r
2076 appData.secondScoreIsAbsolute = FALSE;
\r
2077 appData.saveExtendedInfoInPGN = FALSE;
\r
2078 appData.hideThinkingFromHuman = FALSE;
\r
2079 appData.liteBackTextureFile = "";
\r
2080 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2081 appData.darkBackTextureFile = "";
\r
2082 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2083 appData.renderPiecesWithFont = "";
\r
2084 appData.fontToPieceTable = "";
\r
2085 appData.fontBackColorWhite = 0;
\r
2086 appData.fontForeColorWhite = 0;
\r
2087 appData.fontBackColorBlack = 0;
\r
2088 appData.fontForeColorBlack = 0;
\r
2089 appData.fontPieceSize = 80;
\r
2090 appData.overrideLineGap = 1;
\r
2091 appData.adjudicateLossThreshold = 0;
\r
2092 appData.delayBeforeQuit = 0;
\r
2093 appData.delayAfterQuit = 0;
\r
2094 appData.nameOfDebugFile = "winboard.debug";
\r
2095 appData.pgnEventHeader = "Computer Chess Game";
\r
2096 appData.defaultFrcPosition = -1;
\r
2097 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2098 appData.saveOutOfBookInfo = TRUE;
\r
2099 appData.showEvalInMoveHistory = TRUE;
\r
2100 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2101 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2102 appData.highlightMoveWithArrow = FALSE;
\r
2103 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2104 appData.useStickyWindows = TRUE;
\r
2105 appData.adjudicateDrawMoves = 0;
\r
2106 appData.autoDisplayComment = TRUE;
\r
2107 appData.autoDisplayTags = TRUE;
\r
2108 appData.firstIsUCI = FALSE;
\r
2109 appData.secondIsUCI = FALSE;
\r
2110 appData.firstHasOwnBookUCI = TRUE;
\r
2111 appData.secondHasOwnBookUCI = TRUE;
\r
2112 appData.polyglotDir = "";
\r
2113 appData.usePolyglotBook = FALSE;
\r
2114 appData.polyglotBook = "";
\r
2115 appData.defaultHashSize = 64;
\r
2116 appData.defaultCacheSizeEGTB = 4;
\r
2117 appData.defaultPathEGTB = "c:\\egtb";
\r
2118 appData.firstOptions = "";
\r
2119 appData.secondOptions = "";
\r
2121 InitWindowPlacement( &wpGameList );
\r
2122 InitWindowPlacement( &wpMoveHistory );
\r
2123 InitWindowPlacement( &wpEvalGraph );
\r
2124 InitWindowPlacement( &wpEngineOutput );
\r
2125 InitWindowPlacement( &wpConsole );
\r
2127 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2128 appData.NrFiles = -1;
\r
2129 appData.NrRanks = -1;
\r
2130 appData.holdingsSize = -1;
\r
2131 appData.testClaims = FALSE;
\r
2132 appData.checkMates = FALSE;
\r
2133 appData.materialDraws= FALSE;
\r
2134 appData.trivialDraws = FALSE;
\r
2135 appData.ruleMoves = 51;
\r
2136 appData.drawRepeats = 6;
\r
2137 appData.matchPause = 10000;
\r
2138 appData.alphaRank = FALSE;
\r
2139 appData.allWhite = FALSE;
\r
2140 appData.upsideDown = FALSE;
\r
2141 appData.serverPause = 15;
\r
2142 appData.serverMovesName = NULL;
\r
2143 appData.suppressLoadMoves = FALSE;
\r
2144 appData.firstTimeOdds = 1;
\r
2145 appData.secondTimeOdds = 1;
\r
2146 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2147 appData.secondAccumulateTC = 1;
\r
2148 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2149 appData.secondNPS = -1;
\r
2150 appData.engineComments = 1;
\r
2151 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2152 appData.egtFormats = "";
\r
2155 appData.zippyTalk = ZIPPY_TALK;
\r
2156 appData.zippyPlay = ZIPPY_PLAY;
\r
2157 appData.zippyLines = ZIPPY_LINES;
\r
2158 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2159 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2160 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2161 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2162 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2163 appData.zippyUseI = ZIPPY_USE_I;
\r
2164 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2165 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2166 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2167 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2168 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2169 appData.zippyAbort = ZIPPY_ABORT;
\r
2170 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2171 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2172 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2175 /* Point font array elements to structures and
\r
2176 parse default font names */
\r
2177 for (i=0; i<NUM_FONTS; i++) {
\r
2178 for (j=0; j<NUM_SIZES; j++) {
\r
2179 font[j][i] = &fontRec[j][i];
\r
2180 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2184 /* Parse default settings file if any */
\r
2185 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2186 settingsFileName = strdup(buf);
\r
2189 /* Parse command line */
\r
2190 ParseArgs(StringGet, &lpCmdLine);
\r
2192 /* [HGM] make sure board size is acceptable */
\r
2193 if(appData.NrFiles > BOARD_SIZE ||
\r
2194 appData.NrRanks > BOARD_SIZE )
\r
2195 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2197 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2198 * with options from the command line, we now make an even higher priority
\r
2199 * overrule by WB options attached to the engine command line. This so that
\r
2200 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2203 if(appData.firstChessProgram != NULL) {
\r
2204 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2205 static char *f = "first";
\r
2206 char buf[MSG_SIZ], *q = buf;
\r
2207 if(p != NULL) { // engine command line contains WinBoard options
\r
2208 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2209 ParseArgs(StringGet, &q);
\r
2210 p[-1] = 0; // cut them offengine command line
\r
2213 // now do same for second chess program
\r
2214 if(appData.secondChessProgram != NULL) {
\r
2215 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2216 static char *s = "second";
\r
2217 char buf[MSG_SIZ], *q = buf;
\r
2218 if(p != NULL) { // engine command line contains WinBoard options
\r
2219 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2220 ParseArgs(StringGet, &q);
\r
2221 p[-1] = 0; // cut them offengine command line
\r
2226 /* Propagate options that affect others */
\r
2227 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2228 if (appData.icsActive || appData.noChessProgram) {
\r
2229 chessProgram = FALSE; /* not local chess program mode */
\r
2232 /* Open startup dialog if needed */
\r
2233 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2234 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2235 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2236 *appData.secondChessProgram == NULLCHAR))) {
\r
2239 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2240 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2241 FreeProcInstance(lpProc);
\r
2244 /* Make sure save files land in the right (?) directory */
\r
2245 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2246 appData.saveGameFile = strdup(buf);
\r
2248 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2249 appData.savePositionFile = strdup(buf);
\r
2252 /* Finish initialization for fonts and sounds */
\r
2253 for (i=0; i<NUM_FONTS; i++) {
\r
2254 for (j=0; j<NUM_SIZES; j++) {
\r
2255 CreateFontInMF(font[j][i]);
\r
2258 /* xboard, and older WinBoards, controlled the move sound with the
\r
2259 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2260 always turn the option on (so that the backend will call us),
\r
2261 then let the user turn the sound off by setting it to silence if
\r
2262 desired. To accommodate old winboard.ini files saved by old
\r
2263 versions of WinBoard, we also turn off the sound if the option
\r
2264 was initially set to false. */
\r
2265 if (!appData.ringBellAfterMoves) {
\r
2266 sounds[(int)SoundMove].name = strdup("");
\r
2267 appData.ringBellAfterMoves = TRUE;
\r
2269 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2270 SetCurrentDirectory(installDir);
\r
2272 SetCurrentDirectory(currDir);
\r
2274 p = icsTextMenuString;
\r
2275 if (p[0] == '@') {
\r
2276 FILE* f = fopen(p + 1, "r");
\r
2278 DisplayFatalError(p + 1, errno, 2);
\r
2281 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2283 buf[i] = NULLCHAR;
\r
2286 ParseIcsTextMenu(strdup(p));
\r
2293 HMENU hmenu = GetMenu(hwndMain);
\r
2295 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2296 MF_BYCOMMAND|((appData.icsActive &&
\r
2297 *appData.icsCommPort != NULLCHAR) ?
\r
2298 MF_ENABLED : MF_GRAYED));
\r
2299 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2300 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2301 MF_CHECKED : MF_UNCHECKED));
\r
2306 SaveSettings(char* name)
\r
2309 ArgDescriptor *ad;
\r
2310 WINDOWPLACEMENT wp;
\r
2311 char dir[MSG_SIZ];
\r
2313 if (!hwndMain) return;
\r
2315 GetCurrentDirectory(MSG_SIZ, dir);
\r
2316 SetCurrentDirectory(installDir);
\r
2317 f = fopen(name, "w");
\r
2318 SetCurrentDirectory(dir);
\r
2320 DisplayError(name, errno);
\r
2323 fprintf(f, ";\n");
\r
2324 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2325 fprintf(f, ";\n");
\r
2326 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2327 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2328 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2329 fprintf(f, ";\n");
\r
2331 wp.length = sizeof(WINDOWPLACEMENT);
\r
2332 GetWindowPlacement(hwndMain, &wp);
\r
2333 boardX = wp.rcNormalPosition.left;
\r
2334 boardY = wp.rcNormalPosition.top;
\r
2336 if (hwndConsole) {
\r
2337 GetWindowPlacement(hwndConsole, &wp);
\r
2338 wpConsole.x = wp.rcNormalPosition.left;
\r
2339 wpConsole.y = wp.rcNormalPosition.top;
\r
2340 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2341 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2344 if (analysisDialog) {
\r
2345 GetWindowPlacement(analysisDialog, &wp);
\r
2346 analysisX = wp.rcNormalPosition.left;
\r
2347 analysisY = wp.rcNormalPosition.top;
\r
2348 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2349 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2352 if (commentDialog) {
\r
2353 GetWindowPlacement(commentDialog, &wp);
\r
2354 commentX = wp.rcNormalPosition.left;
\r
2355 commentY = wp.rcNormalPosition.top;
\r
2356 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2357 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2360 if (editTagsDialog) {
\r
2361 GetWindowPlacement(editTagsDialog, &wp);
\r
2362 editTagsX = wp.rcNormalPosition.left;
\r
2363 editTagsY = wp.rcNormalPosition.top;
\r
2364 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2365 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2368 if (gameListDialog) {
\r
2369 GetWindowPlacement(gameListDialog, &wp);
\r
2370 wpGameList.x = wp.rcNormalPosition.left;
\r
2371 wpGameList.y = wp.rcNormalPosition.top;
\r
2372 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2373 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2376 /* [AS] Move history */
\r
2377 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2379 if( moveHistoryDialog ) {
\r
2380 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2381 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2382 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2383 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2384 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2387 /* [AS] Eval graph */
\r
2388 wpEvalGraph.visible = EvalGraphIsUp();
\r
2390 if( evalGraphDialog ) {
\r
2391 GetWindowPlacement(evalGraphDialog, &wp);
\r
2392 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2393 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2394 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2395 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2398 /* [AS] Engine output */
\r
2399 wpEngineOutput.visible = EngineOutputIsUp();
\r
2401 if( engineOutputDialog ) {
\r
2402 GetWindowPlacement(engineOutputDialog, &wp);
\r
2403 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2404 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2405 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2406 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2409 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2410 if (!ad->save) continue;
\r
2411 switch (ad->argType) {
\r
2414 char *p = *(char **)ad->argLoc;
\r
2415 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2416 /* Quote multiline values or \-containing values
\r
2417 with { } if possible */
\r
2418 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2420 /* Else quote with " " */
\r
2421 fprintf(f, "/%s=\"", ad->argName);
\r
2423 if (*p == '\n') fprintf(f, "\n");
\r
2424 else if (*p == '\r') fprintf(f, "\\r");
\r
2425 else if (*p == '\t') fprintf(f, "\\t");
\r
2426 else if (*p == '\b') fprintf(f, "\\b");
\r
2427 else if (*p == '\f') fprintf(f, "\\f");
\r
2428 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2429 else if (*p == '\"') fprintf(f, "\\\"");
\r
2430 else if (*p == '\\') fprintf(f, "\\\\");
\r
2434 fprintf(f, "\"\n");
\r
2440 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2443 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2446 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2449 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2452 fprintf(f, "/%s=%s\n", ad->argName,
\r
2453 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2456 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2463 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2464 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2465 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2470 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2471 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2472 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2473 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2474 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2475 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2476 (ta->effects) ? " " : "",
\r
2477 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2481 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2482 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2484 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2487 case ArgBoardSize:
\r
2488 fprintf(f, "/%s=%s\n", ad->argName,
\r
2489 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2494 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2495 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2496 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2497 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2498 ad->argName, mfp->faceName, mfp->pointSize,
\r
2499 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2500 mfp->bold ? "b" : "",
\r
2501 mfp->italic ? "i" : "",
\r
2502 mfp->underline ? "u" : "",
\r
2503 mfp->strikeout ? "s" : "");
\r
2507 case ArgCommSettings:
\r
2508 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2510 case ArgSettingsFilename: ;
\r
2518 /*---------------------------------------------------------------------------*\
\r
2520 * GDI board drawing routines
\r
2522 \*---------------------------------------------------------------------------*/
\r
2524 /* [AS] Draw square using background texture */
\r
2525 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2530 return; /* Should never happen! */
\r
2533 SetGraphicsMode( dst, GM_ADVANCED );
\r
2540 /* X reflection */
\r
2545 x.eDx = (FLOAT) dw + dx - 1;
\r
2548 SetWorldTransform( dst, &x );
\r
2551 /* Y reflection */
\r
2557 x.eDy = (FLOAT) dh + dy - 1;
\r
2559 SetWorldTransform( dst, &x );
\r
2567 x.eDx = (FLOAT) dx;
\r
2568 x.eDy = (FLOAT) dy;
\r
2571 SetWorldTransform( dst, &x );
\r
2575 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2583 SetWorldTransform( dst, &x );
\r
2585 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2588 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2590 PM_WP = (int) WhitePawn,
\r
2591 PM_WN = (int) WhiteKnight,
\r
2592 PM_WB = (int) WhiteBishop,
\r
2593 PM_WR = (int) WhiteRook,
\r
2594 PM_WQ = (int) WhiteQueen,
\r
2595 PM_WF = (int) WhiteFerz,
\r
2596 PM_WW = (int) WhiteWazir,
\r
2597 PM_WE = (int) WhiteAlfil,
\r
2598 PM_WM = (int) WhiteMan,
\r
2599 PM_WO = (int) WhiteCannon,
\r
2600 PM_WU = (int) WhiteUnicorn,
\r
2601 PM_WH = (int) WhiteNightrider,
\r
2602 PM_WA = (int) WhiteAngel,
\r
2603 PM_WC = (int) WhiteMarshall,
\r
2604 PM_WAB = (int) WhiteCardinal,
\r
2605 PM_WD = (int) WhiteDragon,
\r
2606 PM_WL = (int) WhiteLance,
\r
2607 PM_WS = (int) WhiteCobra,
\r
2608 PM_WV = (int) WhiteFalcon,
\r
2609 PM_WSG = (int) WhiteSilver,
\r
2610 PM_WG = (int) WhiteGrasshopper,
\r
2611 PM_WK = (int) WhiteKing,
\r
2612 PM_BP = (int) BlackPawn,
\r
2613 PM_BN = (int) BlackKnight,
\r
2614 PM_BB = (int) BlackBishop,
\r
2615 PM_BR = (int) BlackRook,
\r
2616 PM_BQ = (int) BlackQueen,
\r
2617 PM_BF = (int) BlackFerz,
\r
2618 PM_BW = (int) BlackWazir,
\r
2619 PM_BE = (int) BlackAlfil,
\r
2620 PM_BM = (int) BlackMan,
\r
2621 PM_BO = (int) BlackCannon,
\r
2622 PM_BU = (int) BlackUnicorn,
\r
2623 PM_BH = (int) BlackNightrider,
\r
2624 PM_BA = (int) BlackAngel,
\r
2625 PM_BC = (int) BlackMarshall,
\r
2626 PM_BG = (int) BlackGrasshopper,
\r
2627 PM_BAB = (int) BlackCardinal,
\r
2628 PM_BD = (int) BlackDragon,
\r
2629 PM_BL = (int) BlackLance,
\r
2630 PM_BS = (int) BlackCobra,
\r
2631 PM_BV = (int) BlackFalcon,
\r
2632 PM_BSG = (int) BlackSilver,
\r
2633 PM_BK = (int) BlackKing
\r
2636 static HFONT hPieceFont = NULL;
\r
2637 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2638 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2639 static int fontBitmapSquareSize = 0;
\r
2640 static char pieceToFontChar[(int) EmptySquare] =
\r
2641 { 'p', 'n', 'b', 'r', 'q',
\r
2642 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2643 'k', 'o', 'm', 'v', 't', 'w',
\r
2644 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2647 extern BOOL SetCharTable( char *table, const char * map );
\r
2648 /* [HGM] moved to backend.c */
\r
2650 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2653 BYTE r1 = GetRValue( color );
\r
2654 BYTE g1 = GetGValue( color );
\r
2655 BYTE b1 = GetBValue( color );
\r
2661 /* Create a uniform background first */
\r
2662 hbrush = CreateSolidBrush( color );
\r
2663 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2664 FillRect( hdc, &rc, hbrush );
\r
2665 DeleteObject( hbrush );
\r
2668 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2669 int steps = squareSize / 2;
\r
2672 for( i=0; i<steps; i++ ) {
\r
2673 BYTE r = r1 - (r1-r2) * i / steps;
\r
2674 BYTE g = g1 - (g1-g2) * i / steps;
\r
2675 BYTE b = b1 - (b1-b2) * i / steps;
\r
2677 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2678 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2679 FillRect( hdc, &rc, hbrush );
\r
2680 DeleteObject(hbrush);
\r
2683 else if( mode == 2 ) {
\r
2684 /* Diagonal gradient, good more or less for every piece */
\r
2685 POINT triangle[3];
\r
2686 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2687 HBRUSH hbrush_old;
\r
2688 int steps = squareSize;
\r
2691 triangle[0].x = squareSize - steps;
\r
2692 triangle[0].y = squareSize;
\r
2693 triangle[1].x = squareSize;
\r
2694 triangle[1].y = squareSize;
\r
2695 triangle[2].x = squareSize;
\r
2696 triangle[2].y = squareSize - steps;
\r
2698 for( i=0; i<steps; i++ ) {
\r
2699 BYTE r = r1 - (r1-r2) * i / steps;
\r
2700 BYTE g = g1 - (g1-g2) * i / steps;
\r
2701 BYTE b = b1 - (b1-b2) * i / steps;
\r
2703 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2704 hbrush_old = SelectObject( hdc, hbrush );
\r
2705 Polygon( hdc, triangle, 3 );
\r
2706 SelectObject( hdc, hbrush_old );
\r
2707 DeleteObject(hbrush);
\r
2712 SelectObject( hdc, hpen );
\r
2717 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2718 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2719 piece: follow the steps as explained below.
\r
2721 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2725 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2729 int backColor = whitePieceColor;
\r
2730 int foreColor = blackPieceColor;
\r
2732 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2733 backColor = appData.fontBackColorWhite;
\r
2734 foreColor = appData.fontForeColorWhite;
\r
2736 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2737 backColor = appData.fontBackColorBlack;
\r
2738 foreColor = appData.fontForeColorBlack;
\r
2742 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2744 hbm_old = SelectObject( hdc, hbm );
\r
2748 rc.right = squareSize;
\r
2749 rc.bottom = squareSize;
\r
2751 /* Step 1: background is now black */
\r
2752 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2754 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2756 pt.x = (squareSize - sz.cx) / 2;
\r
2757 pt.y = (squareSize - sz.cy) / 2;
\r
2759 SetBkMode( hdc, TRANSPARENT );
\r
2760 SetTextColor( hdc, chroma );
\r
2761 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2762 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2764 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2765 /* Step 3: the area outside the piece is filled with white */
\r
2766 // FloodFill( hdc, 0, 0, chroma );
\r
2767 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2768 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2769 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2770 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2771 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2773 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2774 but if the start point is not inside the piece we're lost!
\r
2775 There should be a better way to do this... if we could create a region or path
\r
2776 from the fill operation we would be fine for example.
\r
2778 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2779 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2781 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2782 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2783 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2785 SelectObject( dc2, bm2 );
\r
2786 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2787 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2788 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2790 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2793 DeleteObject( bm2 );
\r
2796 SetTextColor( hdc, 0 );
\r
2798 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2799 draw the piece again in black for safety.
\r
2801 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2803 SelectObject( hdc, hbm_old );
\r
2805 if( hPieceMask[index] != NULL ) {
\r
2806 DeleteObject( hPieceMask[index] );
\r
2809 hPieceMask[index] = hbm;
\r
2812 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2814 SelectObject( hdc, hbm );
\r
2817 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2818 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2819 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2821 SelectObject( dc1, hPieceMask[index] );
\r
2822 SelectObject( dc2, bm2 );
\r
2823 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2824 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2827 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2828 the piece background and deletes (makes transparent) the rest.
\r
2829 Thanks to that mask, we are free to paint the background with the greates
\r
2830 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2831 We use this, to make gradients and give the pieces a "roundish" look.
\r
2833 SetPieceBackground( hdc, backColor, 2 );
\r
2834 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2838 DeleteObject( bm2 );
\r
2841 SetTextColor( hdc, foreColor );
\r
2842 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2844 SelectObject( hdc, hbm_old );
\r
2846 if( hPieceFace[index] != NULL ) {
\r
2847 DeleteObject( hPieceFace[index] );
\r
2850 hPieceFace[index] = hbm;
\r
2853 static int TranslatePieceToFontPiece( int piece )
\r
2883 case BlackMarshall:
\r
2887 case BlackNightrider:
\r
2893 case BlackUnicorn:
\r
2897 case BlackGrasshopper:
\r
2909 case BlackCardinal:
\r
2916 case WhiteMarshall:
\r
2920 case WhiteNightrider:
\r
2926 case WhiteUnicorn:
\r
2930 case WhiteGrasshopper:
\r
2942 case WhiteCardinal:
\r
2951 void CreatePiecesFromFont()
\r
2954 HDC hdc_window = NULL;
\r
2960 if( fontBitmapSquareSize < 0 ) {
\r
2961 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2965 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2966 fontBitmapSquareSize = -1;
\r
2970 if( fontBitmapSquareSize != squareSize ) {
\r
2971 hdc_window = GetDC( hwndMain );
\r
2972 hdc = CreateCompatibleDC( hdc_window );
\r
2974 if( hPieceFont != NULL ) {
\r
2975 DeleteObject( hPieceFont );
\r
2978 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2979 hPieceMask[i] = NULL;
\r
2980 hPieceFace[i] = NULL;
\r
2986 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2987 fontHeight = appData.fontPieceSize;
\r
2990 fontHeight = (fontHeight * squareSize) / 100;
\r
2992 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2994 lf.lfEscapement = 0;
\r
2995 lf.lfOrientation = 0;
\r
2996 lf.lfWeight = FW_NORMAL;
\r
2998 lf.lfUnderline = 0;
\r
2999 lf.lfStrikeOut = 0;
\r
3000 lf.lfCharSet = DEFAULT_CHARSET;
\r
3001 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3002 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3003 lf.lfQuality = PROOF_QUALITY;
\r
3004 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3005 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3006 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3008 hPieceFont = CreateFontIndirect( &lf );
\r
3010 if( hPieceFont == NULL ) {
\r
3011 fontBitmapSquareSize = -2;
\r
3014 /* Setup font-to-piece character table */
\r
3015 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3016 /* No (or wrong) global settings, try to detect the font */
\r
3017 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3019 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3021 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3022 /* DiagramTT* family */
\r
3023 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3025 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3026 /* Fairy symbols */
\r
3027 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3029 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3030 /* Good Companion (Some characters get warped as literal :-( */
\r
3031 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3032 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3033 SetCharTable(pieceToFontChar, s);
\r
3036 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3037 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3041 /* Create bitmaps */
\r
3042 hfont_old = SelectObject( hdc, hPieceFont );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3081 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3082 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3083 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3084 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3085 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3086 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3087 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3088 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3090 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3091 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3092 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3094 SelectObject( hdc, hfont_old );
\r
3096 fontBitmapSquareSize = squareSize;
\r
3100 if( hdc != NULL ) {
\r
3104 if( hdc_window != NULL ) {
\r
3105 ReleaseDC( hwndMain, hdc_window );
\r
3110 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3114 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3115 if (gameInfo.event &&
\r
3116 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3117 strcmp(name, "k80s") == 0) {
\r
3118 strcpy(name, "tim");
\r
3120 return LoadBitmap(hinst, name);
\r
3124 /* Insert a color into the program's logical palette
\r
3125 structure. This code assumes the given color is
\r
3126 the result of the RGB or PALETTERGB macro, and it
\r
3127 knows how those macros work (which is documented).
\r
3130 InsertInPalette(COLORREF color)
\r
3132 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3134 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3135 DisplayFatalError("Too many colors", 0, 1);
\r
3136 pLogPal->palNumEntries--;
\r
3140 pe->peFlags = (char) 0;
\r
3141 pe->peRed = (char) (0xFF & color);
\r
3142 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3143 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3149 InitDrawingColors()
\r
3151 if (pLogPal == NULL) {
\r
3152 /* Allocate enough memory for a logical palette with
\r
3153 * PALETTESIZE entries and set the size and version fields
\r
3154 * of the logical palette structure.
\r
3156 pLogPal = (NPLOGPALETTE)
\r
3157 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3158 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3159 pLogPal->palVersion = 0x300;
\r
3161 pLogPal->palNumEntries = 0;
\r
3163 InsertInPalette(lightSquareColor);
\r
3164 InsertInPalette(darkSquareColor);
\r
3165 InsertInPalette(whitePieceColor);
\r
3166 InsertInPalette(blackPieceColor);
\r
3167 InsertInPalette(highlightSquareColor);
\r
3168 InsertInPalette(premoveHighlightColor);
\r
3170 /* create a logical color palette according the information
\r
3171 * in the LOGPALETTE structure.
\r
3173 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3175 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3176 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3177 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3178 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3179 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3180 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3181 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3182 /* [AS] Force rendering of the font-based pieces */
\r
3183 if( fontBitmapSquareSize > 0 ) {
\r
3184 fontBitmapSquareSize = 0;
\r
3190 BoardWidth(int boardSize, int n)
\r
3191 { /* [HGM] argument n added to allow different width and height */
\r
3192 int lineGap = sizeInfo[boardSize].lineGap;
\r
3194 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3195 lineGap = appData.overrideLineGap;
\r
3198 return (n + 1) * lineGap +
\r
3199 n * sizeInfo[boardSize].squareSize;
\r
3202 /* Respond to board resize by dragging edge */
\r
3204 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3206 BoardSize newSize = NUM_SIZES - 1;
\r
3207 static int recurse = 0;
\r
3208 if (IsIconic(hwndMain)) return;
\r
3209 if (recurse > 0) return;
\r
3211 while (newSize > 0) {
\r
3212 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3213 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3214 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3217 boardSize = newSize;
\r
3218 InitDrawingSizes(boardSize, flags);
\r
3225 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3227 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3228 ChessSquare piece;
\r
3229 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3231 SIZE clockSize, messageSize;
\r
3233 char buf[MSG_SIZ];
\r
3235 HMENU hmenu = GetMenu(hwndMain);
\r
3236 RECT crect, wrect, oldRect;
\r
3238 LOGBRUSH logbrush;
\r
3240 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3241 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3243 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3244 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3246 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3247 oldRect.top = boardY;
\r
3248 oldRect.right = boardX + winWidth;
\r
3249 oldRect.bottom = boardY + winHeight;
\r
3251 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3252 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3253 squareSize = sizeInfo[boardSize].squareSize;
\r
3254 lineGap = sizeInfo[boardSize].lineGap;
\r
3255 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3257 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3258 lineGap = appData.overrideLineGap;
\r
3261 if (tinyLayout != oldTinyLayout) {
\r
3262 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3264 style &= ~WS_SYSMENU;
\r
3265 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3266 "&Minimize\tCtrl+F4");
\r
3268 style |= WS_SYSMENU;
\r
3269 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3271 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3273 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3274 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3275 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3277 DrawMenuBar(hwndMain);
\r
3280 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3281 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3283 /* Get text area sizes */
\r
3284 hdc = GetDC(hwndMain);
\r
3285 if (appData.clockMode) {
\r
3286 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3288 sprintf(buf, "White");
\r
3290 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3291 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3292 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3293 str = "We only care about the height here";
\r
3294 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3295 SelectObject(hdc, oldFont);
\r
3296 ReleaseDC(hwndMain, hdc);
\r
3298 /* Compute where everything goes */
\r
3299 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3300 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3301 logoHeight = 2*clockSize.cy;
\r
3302 leftLogoRect.left = OUTER_MARGIN;
\r
3303 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3304 leftLogoRect.top = OUTER_MARGIN;
\r
3305 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3307 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3308 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3309 rightLogoRect.top = OUTER_MARGIN;
\r
3310 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3313 whiteRect.left = leftLogoRect.right;
\r
3314 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3315 whiteRect.top = OUTER_MARGIN;
\r
3316 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3318 blackRect.right = rightLogoRect.left;
\r
3319 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3320 blackRect.top = whiteRect.top;
\r
3321 blackRect.bottom = whiteRect.bottom;
\r
3323 whiteRect.left = OUTER_MARGIN;
\r
3324 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3325 whiteRect.top = OUTER_MARGIN;
\r
3326 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3328 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3329 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3330 blackRect.top = whiteRect.top;
\r
3331 blackRect.bottom = whiteRect.bottom;
\r
3334 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3335 if (appData.showButtonBar) {
\r
3336 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3337 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3339 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3341 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3342 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3344 boardRect.left = OUTER_MARGIN;
\r
3345 boardRect.right = boardRect.left + boardWidth;
\r
3346 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3347 boardRect.bottom = boardRect.top + boardHeight;
\r
3349 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3350 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3351 oldBoardSize = boardSize;
\r
3352 oldTinyLayout = tinyLayout;
\r
3353 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3354 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3355 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3356 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3357 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3358 winHeight = winH; // without disturbing window attachments
\r
3359 GetWindowRect(hwndMain, &wrect);
\r
3360 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3361 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3363 // [HGM] placement: let attached windows follow size change.
\r
3364 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3365 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3366 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3367 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3368 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3370 /* compensate if menu bar wrapped */
\r
3371 GetClientRect(hwndMain, &crect);
\r
3372 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3373 winHeight += offby;
\r
3375 case WMSZ_TOPLEFT:
\r
3376 SetWindowPos(hwndMain, NULL,
\r
3377 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3378 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3381 case WMSZ_TOPRIGHT:
\r
3383 SetWindowPos(hwndMain, NULL,
\r
3384 wrect.left, wrect.bottom - winHeight,
\r
3385 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3388 case WMSZ_BOTTOMLEFT:
\r
3390 SetWindowPos(hwndMain, NULL,
\r
3391 wrect.right - winWidth, wrect.top,
\r
3392 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3395 case WMSZ_BOTTOMRIGHT:
\r
3399 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3400 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3405 for (i = 0; i < N_BUTTONS; i++) {
\r
3406 if (buttonDesc[i].hwnd != NULL) {
\r
3407 DestroyWindow(buttonDesc[i].hwnd);
\r
3408 buttonDesc[i].hwnd = NULL;
\r
3410 if (appData.showButtonBar) {
\r
3411 buttonDesc[i].hwnd =
\r
3412 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3413 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3414 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3415 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3416 (HMENU) buttonDesc[i].id,
\r
3417 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3419 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3420 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3421 MAKELPARAM(FALSE, 0));
\r
3423 if (buttonDesc[i].id == IDM_Pause)
\r
3424 hwndPause = buttonDesc[i].hwnd;
\r
3425 buttonDesc[i].wndproc = (WNDPROC)
\r
3426 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3429 if (gridPen != NULL) DeleteObject(gridPen);
\r
3430 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3431 if (premovePen != NULL) DeleteObject(premovePen);
\r
3432 if (lineGap != 0) {
\r
3433 logbrush.lbStyle = BS_SOLID;
\r
3434 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3436 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3437 lineGap, &logbrush, 0, NULL);
\r
3438 logbrush.lbColor = highlightSquareColor;
\r
3440 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3441 lineGap, &logbrush, 0, NULL);
\r
3443 logbrush.lbColor = premoveHighlightColor;
\r
3445 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3446 lineGap, &logbrush, 0, NULL);
\r
3448 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3449 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3450 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3451 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3452 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3453 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3454 BOARD_WIDTH * (squareSize + lineGap);
\r
3455 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3457 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3458 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3459 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3460 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3461 lineGap / 2 + (i * (squareSize + lineGap));
\r
3462 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3463 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3464 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3468 /* [HGM] Licensing requirement */
\r
3470 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3473 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3475 GothicPopUp( "", VariantNormal);
\r
3478 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3480 /* Load piece bitmaps for this board size */
\r
3481 for (i=0; i<=2; i++) {
\r
3482 for (piece = WhitePawn;
\r
3483 (int) piece < (int) BlackPawn;
\r
3484 piece = (ChessSquare) ((int) piece + 1)) {
\r
3485 if (pieceBitmap[i][piece] != NULL)
\r
3486 DeleteObject(pieceBitmap[i][piece]);
\r
3490 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3491 // Orthodox Chess pieces
\r
3492 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3493 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3494 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3495 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3496 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3497 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3498 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3499 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3500 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3501 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3502 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3507 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3508 // in Shogi, Hijack the unused Queen for Lance
\r
3509 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3513 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3518 if(squareSize <= 72 && squareSize >= 33) {
\r
3519 /* A & C are available in most sizes now */
\r
3520 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3521 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3530 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3533 } else { // Smirf-like
\r
3534 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3538 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3539 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3542 } else { // WinBoard standard
\r
3543 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3550 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3551 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3560 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3569 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3570 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3571 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3572 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3573 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3574 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3575 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3582 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3583 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3584 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3585 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3586 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3587 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3588 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3589 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3590 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3591 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3592 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3593 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3594 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3596 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3597 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3598 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3599 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3600 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3601 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3602 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3603 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3604 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3605 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3606 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3607 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3610 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3611 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3612 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3613 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3614 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3615 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3616 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3617 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3618 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3619 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3620 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3621 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3622 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3623 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3624 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3628 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3629 /* special Shogi support in this size */
\r
3630 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3631 for (piece = WhitePawn;
\r
3632 (int) piece < (int) BlackPawn;
\r
3633 piece = (ChessSquare) ((int) piece + 1)) {
\r
3634 if (pieceBitmap[i][piece] != NULL)
\r
3635 DeleteObject(pieceBitmap[i][piece]);
\r
3638 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3644 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3645 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3646 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3647 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3648 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3649 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3650 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3651 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3652 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3658 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3659 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3660 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3661 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3662 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3663 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3664 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3665 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3666 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3672 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3673 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3674 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3675 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3676 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3677 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3678 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3679 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3685 PieceBitmap(ChessSquare p, int kind)
\r
3687 if ((int) p >= (int) BlackPawn)
\r
3688 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3690 return pieceBitmap[kind][(int) p];
\r
3693 /***************************************************************/
\r
3695 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3696 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3698 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3699 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3703 SquareToPos(int row, int column, int * x, int * y)
\r
3706 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3707 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3709 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3710 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3715 DrawCoordsOnDC(HDC hdc)
\r
3717 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
3718 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
3719 char str[2] = { NULLCHAR, NULLCHAR };
\r
3720 int oldMode, oldAlign, x, y, start, i;
\r
3724 if (!appData.showCoords)
\r
3727 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3729 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3730 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3731 oldAlign = GetTextAlign(hdc);
\r
3732 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3734 y = boardRect.top + lineGap;
\r
3735 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3737 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3738 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3739 str[0] = files[start + i];
\r
3740 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3741 y += squareSize + lineGap;
\r
3744 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3746 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3747 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3748 str[0] = ranks[start + i];
\r
3749 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3750 x += squareSize + lineGap;
\r
3753 SelectObject(hdc, oldBrush);
\r
3754 SetBkMode(hdc, oldMode);
\r
3755 SetTextAlign(hdc, oldAlign);
\r
3756 SelectObject(hdc, oldFont);
\r
3760 DrawGridOnDC(HDC hdc)
\r
3764 if (lineGap != 0) {
\r
3765 oldPen = SelectObject(hdc, gridPen);
\r
3766 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3767 SelectObject(hdc, oldPen);
\r
3771 #define HIGHLIGHT_PEN 0
\r
3772 #define PREMOVE_PEN 1
\r
3775 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3778 HPEN oldPen, hPen;
\r
3779 if (lineGap == 0) return;
\r
3781 x1 = boardRect.left +
\r
3782 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3783 y1 = boardRect.top +
\r
3784 lineGap/2 + y * (squareSize + lineGap);
\r
3786 x1 = boardRect.left +
\r
3787 lineGap/2 + x * (squareSize + lineGap);
\r
3788 y1 = boardRect.top +
\r
3789 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3791 hPen = pen ? premovePen : highlightPen;
\r
3792 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3793 MoveToEx(hdc, x1, y1, NULL);
\r
3794 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3795 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3796 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3797 LineTo(hdc, x1, y1);
\r
3798 SelectObject(hdc, oldPen);
\r
3802 DrawHighlightsOnDC(HDC hdc)
\r
3805 for (i=0; i<2; i++) {
\r
3806 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3807 DrawHighlightOnDC(hdc, TRUE,
\r
3808 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3811 for (i=0; i<2; i++) {
\r
3812 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3813 premoveHighlightInfo.sq[i].y >= 0) {
\r
3814 DrawHighlightOnDC(hdc, TRUE,
\r
3815 premoveHighlightInfo.sq[i].x,
\r
3816 premoveHighlightInfo.sq[i].y,
\r
3822 /* Note: sqcolor is used only in monoMode */
\r
3823 /* Note that this code is largely duplicated in woptions.c,
\r
3824 function DrawSampleSquare, so that needs to be updated too */
\r
3826 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3828 HBITMAP oldBitmap;
\r
3832 if (appData.blindfold) return;
\r
3834 /* [AS] Use font-based pieces if needed */
\r
3835 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3836 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3837 CreatePiecesFromFont();
\r
3839 if( fontBitmapSquareSize == squareSize ) {
\r
3840 int index = TranslatePieceToFontPiece(piece);
\r
3842 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3846 squareSize, squareSize,
\r
3851 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3855 squareSize, squareSize,
\r
3864 if (appData.monoMode) {
\r
3865 SelectObject(tmphdc, PieceBitmap(piece,
\r
3866 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3867 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3868 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3870 tmpSize = squareSize;
\r
3872 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3873 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3874 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3875 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3876 x += (squareSize - minorSize)>>1;
\r
3877 y += squareSize - minorSize - 2;
\r
3878 tmpSize = minorSize;
\r
3880 if (color || appData.allWhite ) {
\r
3881 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3883 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3884 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3885 if(appData.upsideDown && color==flipView)
\r
3886 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3888 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3890 /* Use black piece color for outline of white pieces */
\r
3891 /* Not sure this looks really good (though xboard does it).
\r
3892 Maybe better to have another selectable color, default black */
\r
3893 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3894 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3895 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3897 /* Use black for outline of white pieces */
\r
3898 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3899 if(appData.upsideDown && color==flipView)
\r
3900 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3902 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3906 /* Use white piece color for details of black pieces */
\r
3907 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3908 WHITE_PIECE ones aren't always the right shape. */
\r
3909 /* Not sure this looks really good (though xboard does it).
\r
3910 Maybe better to have another selectable color, default medium gray? */
\r
3911 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3912 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3913 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3914 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3915 SelectObject(hdc, blackPieceBrush);
\r
3916 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3918 /* Use square color for details of black pieces */
\r
3919 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3920 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3921 if(appData.upsideDown && !flipView)
\r
3922 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3924 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3927 SelectObject(hdc, oldBrush);
\r
3928 SelectObject(tmphdc, oldBitmap);
\r
3932 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3933 int GetBackTextureMode( int algo )
\r
3935 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3939 case BACK_TEXTURE_MODE_PLAIN:
\r
3940 result = 1; /* Always use identity map */
\r
3942 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3943 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3951 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3952 to handle redraws cleanly (as random numbers would always be different).
\r
3954 VOID RebuildTextureSquareInfo()
\r
3964 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3966 if( liteBackTexture != NULL ) {
\r
3967 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3968 lite_w = bi.bmWidth;
\r
3969 lite_h = bi.bmHeight;
\r
3973 if( darkBackTexture != NULL ) {
\r
3974 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3975 dark_w = bi.bmWidth;
\r
3976 dark_h = bi.bmHeight;
\r
3980 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3981 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3982 if( (col + row) & 1 ) {
\r
3984 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3985 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3986 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3987 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3992 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3993 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3994 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3995 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
4002 /* [AS] Arrow highlighting support */
\r
4004 static int A_WIDTH = 5; /* Width of arrow body */
\r
4006 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
4007 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4009 static double Sqr( double x )
\r
4014 static int Round( double x )
\r
4016 return (int) (x + 0.5);
\r
4019 /* Draw an arrow between two points using current settings */
\r
4020 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4023 double dx, dy, j, k, x, y;
\r
4025 if( d_x == s_x ) {
\r
4026 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4028 arrow[0].x = s_x + A_WIDTH;
\r
4031 arrow[1].x = s_x + A_WIDTH;
\r
4032 arrow[1].y = d_y - h;
\r
4034 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4035 arrow[2].y = d_y - h;
\r
4040 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4041 arrow[4].y = d_y - h;
\r
4043 arrow[5].x = s_x - A_WIDTH;
\r
4044 arrow[5].y = d_y - h;
\r
4046 arrow[6].x = s_x - A_WIDTH;
\r
4049 else if( d_y == s_y ) {
\r
4050 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4053 arrow[0].y = s_y + A_WIDTH;
\r
4055 arrow[1].x = d_x - w;
\r
4056 arrow[1].y = s_y + A_WIDTH;
\r
4058 arrow[2].x = d_x - w;
\r
4059 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4064 arrow[4].x = d_x - w;
\r
4065 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4067 arrow[5].x = d_x - w;
\r
4068 arrow[5].y = s_y - A_WIDTH;
\r
4071 arrow[6].y = s_y - A_WIDTH;
\r
4074 /* [AS] Needed a lot of paper for this! :-) */
\r
4075 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4076 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4078 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4080 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4085 arrow[0].x = Round(x - j);
\r
4086 arrow[0].y = Round(y + j*dx);
\r
4088 arrow[1].x = Round(x + j);
\r
4089 arrow[1].y = Round(y - j*dx);
\r
4092 x = (double) d_x - k;
\r
4093 y = (double) d_y - k*dy;
\r
4096 x = (double) d_x + k;
\r
4097 y = (double) d_y + k*dy;
\r
4100 arrow[2].x = Round(x + j);
\r
4101 arrow[2].y = Round(y - j*dx);
\r
4103 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4104 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4109 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4110 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4112 arrow[6].x = Round(x - j);
\r
4113 arrow[6].y = Round(y + j*dx);
\r
4116 Polygon( hdc, arrow, 7 );
\r
4119 /* [AS] Draw an arrow between two squares */
\r
4120 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4122 int s_x, s_y, d_x, d_y;
\r
4129 if( s_col == d_col && s_row == d_row ) {
\r
4133 /* Get source and destination points */
\r
4134 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4135 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4138 d_y += squareSize / 4;
\r
4140 else if( d_y < s_y ) {
\r
4141 d_y += 3 * squareSize / 4;
\r
4144 d_y += squareSize / 2;
\r
4148 d_x += squareSize / 4;
\r
4150 else if( d_x < s_x ) {
\r
4151 d_x += 3 * squareSize / 4;
\r
4154 d_x += squareSize / 2;
\r
4157 s_x += squareSize / 2;
\r
4158 s_y += squareSize / 2;
\r
4160 /* Adjust width */
\r
4161 A_WIDTH = squareSize / 14;
\r
4164 stLB.lbStyle = BS_SOLID;
\r
4165 stLB.lbColor = appData.highlightArrowColor;
\r
4168 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4169 holdpen = SelectObject( hdc, hpen );
\r
4170 hbrush = CreateBrushIndirect( &stLB );
\r
4171 holdbrush = SelectObject( hdc, hbrush );
\r
4173 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4175 SelectObject( hdc, holdpen );
\r
4176 SelectObject( hdc, holdbrush );
\r
4177 DeleteObject( hpen );
\r
4178 DeleteObject( hbrush );
\r
4181 BOOL HasHighlightInfo()
\r
4183 BOOL result = FALSE;
\r
4185 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4186 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4194 BOOL IsDrawArrowEnabled()
\r
4196 BOOL result = FALSE;
\r
4198 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4205 VOID DrawArrowHighlight( HDC hdc )
\r
4207 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4208 DrawArrowBetweenSquares( hdc,
\r
4209 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4210 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4214 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4216 HRGN result = NULL;
\r
4218 if( HasHighlightInfo() ) {
\r
4219 int x1, y1, x2, y2;
\r
4220 int sx, sy, dx, dy;
\r
4222 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4223 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4225 sx = MIN( x1, x2 );
\r
4226 sy = MIN( y1, y2 );
\r
4227 dx = MAX( x1, x2 ) + squareSize;
\r
4228 dy = MAX( y1, y2 ) + squareSize;
\r
4230 result = CreateRectRgn( sx, sy, dx, dy );
\r
4237 Warning: this function modifies the behavior of several other functions.
\r
4239 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4240 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4241 repaint is scattered all over the place, which is not good for features such as
\r
4242 "arrow highlighting" that require a full repaint of the board.
\r
4244 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4245 user interaction, when speed is not so important) but especially to avoid errors
\r
4246 in the displayed graphics.
\r
4248 In such patched places, I always try refer to this function so there is a single
\r
4249 place to maintain knowledge.
\r
4251 To restore the original behavior, just return FALSE unconditionally.
\r
4253 BOOL IsFullRepaintPreferrable()
\r
4255 BOOL result = FALSE;
\r
4257 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4258 /* Arrow may appear on the board */
\r
4266 This function is called by DrawPosition to know whether a full repaint must
\r
4269 Only DrawPosition may directly call this function, which makes use of
\r
4270 some state information. Other function should call DrawPosition specifying
\r
4271 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4273 BOOL DrawPositionNeedsFullRepaint()
\r
4275 BOOL result = FALSE;
\r
4278 Probably a slightly better policy would be to trigger a full repaint
\r
4279 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4280 but animation is fast enough that it's difficult to notice.
\r
4282 if( animInfo.piece == EmptySquare ) {
\r
4283 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4292 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4294 int row, column, x, y, square_color, piece_color;
\r
4295 ChessSquare piece;
\r
4297 HDC texture_hdc = NULL;
\r
4299 /* [AS] Initialize background textures if needed */
\r
4300 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4301 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4302 if( backTextureSquareSize != squareSize
\r
4303 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4304 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4305 backTextureSquareSize = squareSize;
\r
4306 RebuildTextureSquareInfo();
\r
4309 texture_hdc = CreateCompatibleDC( hdc );
\r
4312 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4313 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4315 SquareToPos(row, column, &x, &y);
\r
4317 piece = board[row][column];
\r
4319 square_color = ((column + row) % 2) == 1;
\r
4320 if( gameInfo.variant == VariantXiangqi ) {
\r
4321 square_color = !InPalace(row, column);
\r
4322 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4323 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4325 piece_color = (int) piece < (int) BlackPawn;
\r
4328 /* [HGM] holdings file: light square or black */
\r
4329 if(column == BOARD_LEFT-2) {
\r
4330 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4333 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4337 if(column == BOARD_RGHT + 1 ) {
\r
4338 if( row < gameInfo.holdingsSize )
\r
4341 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4345 if(column == BOARD_LEFT-1 ) /* left align */
\r
4346 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4347 else if( column == BOARD_RGHT) /* right align */
\r
4348 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4350 if (appData.monoMode) {
\r
4351 if (piece == EmptySquare) {
\r
4352 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4353 square_color ? WHITENESS : BLACKNESS);
\r
4355 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4358 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4359 /* [AS] Draw the square using a texture bitmap */
\r
4360 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4361 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4362 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4365 squareSize, squareSize,
\r
4368 backTextureSquareInfo[r][c].mode,
\r
4369 backTextureSquareInfo[r][c].x,
\r
4370 backTextureSquareInfo[r][c].y );
\r
4372 SelectObject( texture_hdc, hbm );
\r
4374 if (piece != EmptySquare) {
\r
4375 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4379 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4381 oldBrush = SelectObject(hdc, brush );
\r
4382 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4383 SelectObject(hdc, oldBrush);
\r
4384 if (piece != EmptySquare)
\r
4385 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4390 if( texture_hdc != NULL ) {
\r
4391 DeleteDC( texture_hdc );
\r
4395 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4396 void fputDW(FILE *f, int x)
\r
4398 fputc(x & 255, f);
\r
4399 fputc(x>>8 & 255, f);
\r
4400 fputc(x>>16 & 255, f);
\r
4401 fputc(x>>24 & 255, f);
\r
4404 #define MAX_CLIPS 200 /* more than enough */
\r
4407 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4409 // HBITMAP bufferBitmap;
\r
4414 int w = 100, h = 50;
\r
4416 if(logo == NULL) return;
\r
4417 // GetClientRect(hwndMain, &Rect);
\r
4418 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4419 // Rect.bottom-Rect.top+1);
\r
4420 tmphdc = CreateCompatibleDC(hdc);
\r
4421 hbm = SelectObject(tmphdc, logo);
\r
4422 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4426 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4427 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4428 SelectObject(tmphdc, hbm);
\r
4433 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4435 static Board lastReq, lastDrawn;
\r
4436 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4437 static int lastDrawnFlipView = 0;
\r
4438 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4439 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4442 HBITMAP bufferBitmap;
\r
4443 HBITMAP oldBitmap;
\r
4445 HRGN clips[MAX_CLIPS];
\r
4446 ChessSquare dragged_piece = EmptySquare;
\r
4448 /* I'm undecided on this - this function figures out whether a full
\r
4449 * repaint is necessary on its own, so there's no real reason to have the
\r
4450 * caller tell it that. I think this can safely be set to FALSE - but
\r
4451 * if we trust the callers not to request full repaints unnessesarily, then
\r
4452 * we could skip some clipping work. In other words, only request a full
\r
4453 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4454 * gamestart and similar) --Hawk
\r
4456 Boolean fullrepaint = repaint;
\r
4458 if( DrawPositionNeedsFullRepaint() ) {
\r
4459 fullrepaint = TRUE;
\r
4463 if( fullrepaint ) {
\r
4464 static int repaint_count = 0;
\r
4468 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4469 OutputDebugString( buf );
\r
4473 if (board == NULL) {
\r
4474 if (!lastReqValid) {
\r
4479 CopyBoard(lastReq, board);
\r
4483 if (doingSizing) {
\r
4487 if (IsIconic(hwndMain)) {
\r
4491 if (hdc == NULL) {
\r
4492 hdc = GetDC(hwndMain);
\r
4493 if (!appData.monoMode) {
\r
4494 SelectPalette(hdc, hPal, FALSE);
\r
4495 RealizePalette(hdc);
\r
4499 releaseDC = FALSE;
\r
4503 fprintf(debugFP, "*******************************\n"
\r
4505 "dragInfo.from (%d,%d)\n"
\r
4506 "dragInfo.start (%d,%d)\n"
\r
4507 "dragInfo.pos (%d,%d)\n"
\r
4508 "dragInfo.lastpos (%d,%d)\n",
\r
4509 repaint ? "TRUE" : "FALSE",
\r
4510 dragInfo.from.x, dragInfo.from.y,
\r
4511 dragInfo.start.x, dragInfo.start.y,
\r
4512 dragInfo.pos.x, dragInfo.pos.y,
\r
4513 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4514 fprintf(debugFP, "prev: ");
\r
4515 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4516 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4517 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4520 fprintf(debugFP, "\n");
\r
4521 fprintf(debugFP, "board: ");
\r
4522 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4523 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4524 fprintf(debugFP, "%d ", board[row][column]);
\r
4527 fprintf(debugFP, "\n");
\r
4531 /* Create some work-DCs */
\r
4532 hdcmem = CreateCompatibleDC(hdc);
\r
4533 tmphdc = CreateCompatibleDC(hdc);
\r
4535 /* If dragging is in progress, we temporarely remove the piece */
\r
4536 /* [HGM] or temporarily decrease count if stacked */
\r
4537 /* !! Moved to before board compare !! */
\r
4538 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4539 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4540 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4541 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4542 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4544 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4545 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4546 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4548 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4551 /* Figure out which squares need updating by comparing the
\r
4552 * newest board with the last drawn board and checking if
\r
4553 * flipping has changed.
\r
4555 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4556 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4557 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4558 if (lastDrawn[row][column] != board[row][column]) {
\r
4559 SquareToPos(row, column, &x, &y);
\r
4560 clips[num_clips++] =
\r
4561 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4565 for (i=0; i<2; i++) {
\r
4566 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4567 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4568 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4569 lastDrawnHighlight.sq[i].y >= 0) {
\r
4570 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4571 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4572 clips[num_clips++] =
\r
4573 CreateRectRgn(x - lineGap, y - lineGap,
\r
4574 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4576 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4577 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4578 clips[num_clips++] =
\r
4579 CreateRectRgn(x - lineGap, y - lineGap,
\r
4580 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4584 for (i=0; i<2; i++) {
\r
4585 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4586 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4587 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4588 lastDrawnPremove.sq[i].y >= 0) {
\r
4589 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4590 lastDrawnPremove.sq[i].x, &x, &y);
\r
4591 clips[num_clips++] =
\r
4592 CreateRectRgn(x - lineGap, y - lineGap,
\r
4593 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4595 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4596 premoveHighlightInfo.sq[i].y >= 0) {
\r
4597 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4598 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4599 clips[num_clips++] =
\r
4600 CreateRectRgn(x - lineGap, y - lineGap,
\r
4601 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4606 fullrepaint = TRUE;
\r
4609 /* Create a buffer bitmap - this is the actual bitmap
\r
4610 * being written to. When all the work is done, we can
\r
4611 * copy it to the real DC (the screen). This avoids
\r
4612 * the problems with flickering.
\r
4614 GetClientRect(hwndMain, &Rect);
\r
4615 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4616 Rect.bottom-Rect.top+1);
\r
4617 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4618 if (!appData.monoMode) {
\r
4619 SelectPalette(hdcmem, hPal, FALSE);
\r
4622 /* Create clips for dragging */
\r
4623 if (!fullrepaint) {
\r
4624 if (dragInfo.from.x >= 0) {
\r
4625 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4626 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4628 if (dragInfo.start.x >= 0) {
\r
4629 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4630 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4632 if (dragInfo.pos.x >= 0) {
\r
4633 x = dragInfo.pos.x - squareSize / 2;
\r
4634 y = dragInfo.pos.y - squareSize / 2;
\r
4635 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4637 if (dragInfo.lastpos.x >= 0) {
\r
4638 x = dragInfo.lastpos.x - squareSize / 2;
\r
4639 y = dragInfo.lastpos.y - squareSize / 2;
\r
4640 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4644 /* Are we animating a move?
\r
4646 * - remove the piece from the board (temporarely)
\r
4647 * - calculate the clipping region
\r
4649 if (!fullrepaint) {
\r
4650 if (animInfo.piece != EmptySquare) {
\r
4651 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4652 x = boardRect.left + animInfo.lastpos.x;
\r
4653 y = boardRect.top + animInfo.lastpos.y;
\r
4654 x2 = boardRect.left + animInfo.pos.x;
\r
4655 y2 = boardRect.top + animInfo.pos.y;
\r
4656 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4657 /* Slight kludge. The real problem is that after AnimateMove is
\r
4658 done, the position on the screen does not match lastDrawn.
\r
4659 This currently causes trouble only on e.p. captures in
\r
4660 atomic, where the piece moves to an empty square and then
\r
4661 explodes. The old and new positions both had an empty square
\r
4662 at the destination, but animation has drawn a piece there and
\r
4663 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4664 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4668 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4669 if (num_clips == 0)
\r
4670 fullrepaint = TRUE;
\r
4672 /* Set clipping on the memory DC */
\r
4673 if (!fullrepaint) {
\r
4674 SelectClipRgn(hdcmem, clips[0]);
\r
4675 for (x = 1; x < num_clips; x++) {
\r
4676 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4677 abort(); // this should never ever happen!
\r
4681 /* Do all the drawing to the memory DC */
\r
4682 if(explodeInfo.radius) { // [HGM] atomic
\r
4684 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4685 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4686 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4687 x += squareSize/2;
\r
4688 y += squareSize/2;
\r
4689 if(!fullrepaint) {
\r
4690 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4691 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4693 DrawGridOnDC(hdcmem);
\r
4694 DrawHighlightsOnDC(hdcmem);
\r
4695 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4696 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4697 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4698 SelectObject(hdcmem, oldBrush);
\r
4700 DrawGridOnDC(hdcmem);
\r
4701 DrawHighlightsOnDC(hdcmem);
\r
4702 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4705 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4706 if(appData.autoLogo) {
\r
4708 switch(gameMode) { // pick logos based on game mode
\r
4709 case IcsObserving:
\r
4710 whiteLogo = second.programLogo; // ICS logo
\r
4711 blackLogo = second.programLogo;
\r
4714 case IcsPlayingWhite:
\r
4715 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4716 blackLogo = second.programLogo; // ICS logo
\r
4718 case IcsPlayingBlack:
\r
4719 whiteLogo = second.programLogo; // ICS logo
\r
4720 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4722 case TwoMachinesPlay:
\r
4723 if(first.twoMachinesColor[0] == 'b') {
\r
4724 whiteLogo = second.programLogo;
\r
4725 blackLogo = first.programLogo;
\r
4728 case MachinePlaysWhite:
\r
4729 blackLogo = userLogo;
\r
4731 case MachinePlaysBlack:
\r
4732 whiteLogo = userLogo;
\r
4733 blackLogo = first.programLogo;
\r
4736 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4737 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4740 if( appData.highlightMoveWithArrow ) {
\r
4741 DrawArrowHighlight(hdcmem);
\r
4744 DrawCoordsOnDC(hdcmem);
\r
4746 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4747 /* to make sure lastDrawn contains what is actually drawn */
\r
4749 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4750 if (dragged_piece != EmptySquare) {
\r
4751 /* [HGM] or restack */
\r
4752 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4753 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4755 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4756 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4757 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4758 x = dragInfo.pos.x - squareSize / 2;
\r
4759 y = dragInfo.pos.y - squareSize / 2;
\r
4760 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4761 ((int) dragged_piece < (int) BlackPawn),
\r
4762 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4765 /* Put the animated piece back into place and draw it */
\r
4766 if (animInfo.piece != EmptySquare) {
\r
4767 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4768 x = boardRect.left + animInfo.pos.x;
\r
4769 y = boardRect.top + animInfo.pos.y;
\r
4770 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4771 ((int) animInfo.piece < (int) BlackPawn),
\r
4772 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4775 /* Release the bufferBitmap by selecting in the old bitmap
\r
4776 * and delete the memory DC
\r
4778 SelectObject(hdcmem, oldBitmap);
\r
4781 /* Set clipping on the target DC */
\r
4782 if (!fullrepaint) {
\r
4783 SelectClipRgn(hdc, clips[0]);
\r
4784 for (x = 1; x < num_clips; x++) {
\r
4785 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4786 abort(); // this should never ever happen!
\r
4790 /* Copy the new bitmap onto the screen in one go.
\r
4791 * This way we avoid any flickering
\r
4793 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4794 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4795 boardRect.right - boardRect.left,
\r
4796 boardRect.bottom - boardRect.top,
\r
4797 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4798 if(saveDiagFlag) {
\r
4799 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4800 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4802 GetObject(bufferBitmap, sizeof(b), &b);
\r
4803 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4804 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4805 bih.biWidth = b.bmWidth;
\r
4806 bih.biHeight = b.bmHeight;
\r
4808 bih.biBitCount = b.bmBitsPixel;
\r
4809 bih.biCompression = 0;
\r
4810 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4811 bih.biXPelsPerMeter = 0;
\r
4812 bih.biYPelsPerMeter = 0;
\r
4813 bih.biClrUsed = 0;
\r
4814 bih.biClrImportant = 0;
\r
4815 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4816 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4817 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4818 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4821 wb = b.bmWidthBytes;
\r
4823 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4824 int k = ((int*) pData)[i];
\r
4825 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4826 if(j >= 16) break;
\r
4828 if(j >= nrColors) nrColors = j+1;
\r
4830 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4832 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4833 for(w=0; w<(wb>>2); w+=2) {
\r
4834 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4835 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4836 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4837 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4838 pData[p++] = m | j<<4;
\r
4840 while(p&3) pData[p++] = 0;
\r
4843 wb = ((wb+31)>>5)<<2;
\r
4845 // write BITMAPFILEHEADER
\r
4846 fprintf(diagFile, "BM");
\r
4847 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4848 fputDW(diagFile, 0);
\r
4849 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4850 // write BITMAPINFOHEADER
\r
4851 fputDW(diagFile, 40);
\r
4852 fputDW(diagFile, b.bmWidth);
\r
4853 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4854 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4855 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4856 fputDW(diagFile, 0);
\r
4857 fputDW(diagFile, 0);
\r
4858 fputDW(diagFile, 0);
\r
4859 fputDW(diagFile, 0);
\r
4860 fputDW(diagFile, 0);
\r
4861 fputDW(diagFile, 0);
\r
4862 // write color table
\r
4864 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4865 // write bitmap data
\r
4866 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4867 fputc(pData[i], diagFile);
\r
4872 SelectObject(tmphdc, oldBitmap);
\r
4874 /* Massive cleanup */
\r
4875 for (x = 0; x < num_clips; x++)
\r
4876 DeleteObject(clips[x]);
\r
4879 DeleteObject(bufferBitmap);
\r
4882 ReleaseDC(hwndMain, hdc);
\r
4884 if (lastDrawnFlipView != flipView) {
\r
4886 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4888 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4891 /* CopyBoard(lastDrawn, board);*/
\r
4892 lastDrawnHighlight = highlightInfo;
\r
4893 lastDrawnPremove = premoveHighlightInfo;
\r
4894 lastDrawnFlipView = flipView;
\r
4895 lastDrawnValid = 1;
\r
4898 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4903 saveDiagFlag = 1; diagFile = f;
\r
4904 HDCDrawPosition(NULL, TRUE, NULL);
\r
4908 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4915 /*---------------------------------------------------------------------------*\
\r
4916 | CLIENT PAINT PROCEDURE
\r
4917 | This is the main event-handler for the WM_PAINT message.
\r
4919 \*---------------------------------------------------------------------------*/
\r
4921 PaintProc(HWND hwnd)
\r
4927 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4928 if (IsIconic(hwnd)) {
\r
4929 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4931 if (!appData.monoMode) {
\r
4932 SelectPalette(hdc, hPal, FALSE);
\r
4933 RealizePalette(hdc);
\r
4935 HDCDrawPosition(hdc, 1, NULL);
\r
4937 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4938 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4939 ETO_CLIPPED|ETO_OPAQUE,
\r
4940 &messageRect, messageText, strlen(messageText), NULL);
\r
4941 SelectObject(hdc, oldFont);
\r
4942 DisplayBothClocks();
\r
4944 EndPaint(hwnd,&ps);
\r
4952 * If the user selects on a border boundary, return -1; if off the board,
\r
4953 * return -2. Otherwise map the event coordinate to the square.
\r
4954 * The offset boardRect.left or boardRect.top must already have been
\r
4955 * subtracted from x.
\r
4958 EventToSquare(int x)
\r
4965 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4967 x /= (squareSize + lineGap);
\r
4968 if (x >= BOARD_SIZE)
\r
4979 DropEnable dropEnables[] = {
\r
4980 { 'P', DP_Pawn, "Pawn" },
\r
4981 { 'N', DP_Knight, "Knight" },
\r
4982 { 'B', DP_Bishop, "Bishop" },
\r
4983 { 'R', DP_Rook, "Rook" },
\r
4984 { 'Q', DP_Queen, "Queen" },
\r
4988 SetupDropMenu(HMENU hmenu)
\r
4990 int i, count, enable;
\r
4992 extern char white_holding[], black_holding[];
\r
4993 char item[MSG_SIZ];
\r
4995 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4996 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4997 dropEnables[i].piece);
\r
4999 while (p && *p++ == dropEnables[i].piece) count++;
\r
5000 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
5001 enable = count > 0 || !appData.testLegality
\r
5002 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
5003 && !appData.icsActive);
\r
5004 ModifyMenu(hmenu, dropEnables[i].command,
\r
5005 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
5006 dropEnables[i].command, item);
\r
5010 /* Event handler for mouse messages */
\r
5012 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5016 static int recursive = 0;
\r
5018 // BOOLEAN needsRedraw = FALSE;
\r
5019 BOOLEAN saveAnimate;
\r
5020 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5021 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5022 ChessMove moveType;
\r
5025 if (message == WM_MBUTTONUP) {
\r
5026 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5027 to the middle button: we simulate pressing the left button too!
\r
5029 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5030 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5036 pt.x = LOWORD(lParam);
\r
5037 pt.y = HIWORD(lParam);
\r
5038 x = EventToSquare(pt.x - boardRect.left);
\r
5039 y = EventToSquare(pt.y - boardRect.top);
\r
5040 if (!flipView && y >= 0) {
\r
5041 y = BOARD_HEIGHT - 1 - y;
\r
5043 if (flipView && x >= 0) {
\r
5044 x = BOARD_WIDTH - 1 - x;
\r
5047 switch (message) {
\r
5048 case WM_LBUTTONDOWN:
\r
5049 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5050 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5051 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5052 if(gameInfo.holdingsWidth &&
\r
5053 (WhiteOnMove(currentMove)
\r
5054 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5055 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5056 // click in right holdings, for determining promotion piece
\r
5057 ChessSquare p = boards[currentMove][y][x];
\r
5058 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5059 if(p != EmptySquare) {
\r
5060 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5061 fromX = fromY = -1;
\r
5065 DrawPosition(FALSE, boards[currentMove]);
\r
5069 sameAgain = FALSE;
\r
5071 /* Downclick vertically off board; check if on clock */
\r
5072 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5073 if (gameMode == EditPosition) {
\r
5074 SetWhiteToPlayEvent();
\r
5075 } else if (gameMode == IcsPlayingBlack ||
\r
5076 gameMode == MachinePlaysWhite) {
\r
5078 } else if (gameMode == EditGame) {
\r
5079 AdjustClock(flipClock, -1);
\r
5081 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5082 if (gameMode == EditPosition) {
\r
5083 SetBlackToPlayEvent();
\r
5084 } else if (gameMode == IcsPlayingWhite ||
\r
5085 gameMode == MachinePlaysBlack) {
\r
5087 } else if (gameMode == EditGame) {
\r
5088 AdjustClock(!flipClock, -1);
\r
5091 if (!appData.highlightLastMove) {
\r
5092 ClearHighlights();
\r
5093 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5095 fromX = fromY = -1;
\r
5096 dragInfo.start.x = dragInfo.start.y = -1;
\r
5097 dragInfo.from = dragInfo.start;
\r
5099 } else if (x < 0 || y < 0
\r
5100 /* [HGM] block clicks between board and holdings */
\r
5101 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5102 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5103 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5104 /* EditPosition, empty square, or different color piece;
\r
5105 click-click move is possible */
\r
5108 } else if (fromX == x && fromY == y) {
\r
5109 /* Downclick on same square again */
\r
5110 ClearHighlights();
\r
5111 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5113 } else if (fromX != -1 &&
\r
5114 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5116 /* Downclick on different square. */
\r
5117 /* [HGM] if on holdings file, should count as new first click ! */
\r
5118 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5121 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5122 to make sure move is legal before showing promotion popup */
\r
5123 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5124 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5125 fromX = fromY = -1;
\r
5126 ClearHighlights();
\r
5127 DrawPosition(FALSE, boards[currentMove]);
\r
5130 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5131 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5132 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5133 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5134 appData.alwaysPromoteToQueen)) {
\r
5135 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5136 if (!appData.highlightLastMove) {
\r
5137 ClearHighlights();
\r
5138 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5141 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5142 SetHighlights(fromX, fromY, toX, toY);
\r
5143 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5144 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5145 If promotion to Q is legal, all are legal! */
\r
5146 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5147 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5148 // kludge to temporarily execute move on display, without promoting yet
\r
5149 promotionChoice = TRUE;
\r
5150 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5151 boards[currentMove][toY][toX] = p;
\r
5152 DrawPosition(FALSE, boards[currentMove]);
\r
5153 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5154 boards[currentMove][toY][toX] = q;
\r
5155 DisplayMessage("Select piece from holdings", "");
\r
5157 PromotionPopup(hwnd);
\r
5159 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5160 if (appData.animate || appData.highlightLastMove) {
\r
5161 SetHighlights(fromX, fromY, toX, toY);
\r
5163 ClearHighlights();
\r
5165 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5166 if (appData.animate && !appData.highlightLastMove) {
\r
5167 ClearHighlights();
\r
5168 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5171 fromX = fromY = -1;
\r
5175 if (gotPremove && moveType != Comment) {
\r
5176 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5177 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5178 } else ClearHighlights();
\r
5179 fromX = fromY = -1;
\r
5180 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5181 if(moveType != Comment) break;
\r
5183 /* First downclick, or restart on a square with same color piece */
\r
5184 if (!frozen && OKToStartUserMove(x, y)) {
\r
5187 dragInfo.lastpos = pt;
\r
5188 dragInfo.from.x = fromX;
\r
5189 dragInfo.from.y = fromY;
\r
5190 dragInfo.start = dragInfo.from;
\r
5191 SetCapture(hwndMain);
\r
5193 fromX = fromY = -1;
\r
5194 dragInfo.start.x = dragInfo.start.y = -1;
\r
5195 dragInfo.from = dragInfo.start;
\r
5196 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5200 case WM_LBUTTONUP:
\r
5202 if (fromX == -1) break;
\r
5203 if (x == fromX && y == fromY) {
\r
5204 dragInfo.from.x = dragInfo.from.y = -1;
\r
5205 /* Upclick on same square */
\r
5207 /* Clicked same square twice: abort click-click move */
\r
5208 fromX = fromY = -1;
\r
5210 ClearPremoveHighlights();
\r
5212 /* First square clicked: start click-click move */
\r
5213 SetHighlights(fromX, fromY, -1, -1);
\r
5215 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5216 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5217 /* Errant click; ignore */
\r
5220 /* Finish drag move. */
\r
5221 if (appData.debugMode) {
\r
5222 fprintf(debugFP, "release\n");
\r
5224 dragInfo.from.x = dragInfo.from.y = -1;
\r
5227 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5228 appData.animate = appData.animate && !appData.animateDragging;
\r
5229 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5230 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5231 fromX = fromY = -1;
\r
5232 ClearHighlights();
\r
5233 DrawPosition(FALSE, boards[currentMove]);
\r
5234 appData.animate = saveAnimate;
\r
5237 if(moveType != ImpossibleMove) {
\r
5238 /* [HGM] use move type to determine if move is promotion.
\r
5239 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5240 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5241 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5242 appData.alwaysPromoteToQueen))
\r
5243 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5245 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5246 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5247 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5248 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5249 // kludge to temporarily execute move on display, wthout promotng yet
\r
5250 promotionChoice = TRUE;
\r
5251 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5252 boards[currentMove][toY][toX] = p;
\r
5253 DrawPosition(FALSE, boards[currentMove]);
\r
5254 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5255 boards[currentMove][toY][toX] = q;
\r
5256 appData.animate = saveAnimate;
\r
5257 DisplayMessage("Select piece from holdings", "");
\r
5260 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5262 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5263 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5264 moveType == WhiteCapturesEnPassant ||
\r
5265 moveType == BlackCapturesEnPassant ) )
\r
5266 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5267 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5270 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5271 appData.animate = saveAnimate;
\r
5272 fromX = fromY = -1;
\r
5273 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5274 ClearHighlights();
\r
5276 if (appData.animate || appData.animateDragging ||
\r
5277 appData.highlightDragging || gotPremove) {
\r
5278 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5281 dragInfo.start.x = dragInfo.start.y = -1;
\r
5282 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5285 case WM_MOUSEMOVE:
\r
5286 if ((appData.animateDragging || appData.highlightDragging)
\r
5287 && (wParam & MK_LBUTTON)
\r
5288 && dragInfo.from.x >= 0)
\r
5290 BOOL full_repaint = FALSE;
\r
5292 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5293 if (appData.animateDragging) {
\r
5294 dragInfo.pos = pt;
\r
5296 if (appData.highlightDragging) {
\r
5297 SetHighlights(fromX, fromY, x, y);
\r
5298 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5299 full_repaint = TRUE;
\r
5303 DrawPosition( full_repaint, NULL);
\r
5305 dragInfo.lastpos = dragInfo.pos;
\r
5309 case WM_MOUSEWHEEL: // [DM]
\r
5310 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5311 /* Mouse Wheel is being rolled forward
\r
5312 * Play moves forward
\r
5314 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5315 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5316 /* Mouse Wheel is being rolled backward
\r
5317 * Play moves backward
\r
5319 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5320 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5324 case WM_MBUTTONDOWN:
\r
5325 case WM_RBUTTONDOWN:
\r
5328 fromX = fromY = -1;
\r
5329 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5330 dragInfo.start.x = dragInfo.start.y = -1;
\r
5331 dragInfo.from = dragInfo.start;
\r
5332 dragInfo.lastpos = dragInfo.pos;
\r
5333 if (appData.highlightDragging) {
\r
5334 ClearHighlights();
\r
5337 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5338 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5339 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5340 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5341 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5344 DrawPosition(TRUE, NULL);
\r
5346 switch (gameMode) {
\r
5347 case EditPosition:
\r
5348 case IcsExamining:
\r
5349 if (x < 0 || y < 0) break;
\r
5352 if (message == WM_MBUTTONDOWN) {
\r
5353 buttonCount = 3; /* even if system didn't think so */
\r
5354 if (wParam & MK_SHIFT)
\r
5355 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5357 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5358 } else { /* message == WM_RBUTTONDOWN */
\r
5360 if (buttonCount == 3) {
\r
5361 if (wParam & MK_SHIFT)
\r
5362 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5364 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5366 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5369 /* Just have one menu, on the right button. Windows users don't
\r
5370 think to try the middle one, and sometimes other software steals
\r
5371 it, or it doesn't really exist. */
\r
5372 if(gameInfo.variant != VariantShogi)
\r
5373 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5375 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5379 case IcsPlayingWhite:
\r
5380 case IcsPlayingBlack:
\r
5382 case MachinePlaysWhite:
\r
5383 case MachinePlaysBlack:
\r
5384 if (appData.testLegality &&
\r
5385 gameInfo.variant != VariantBughouse &&
\r
5386 gameInfo.variant != VariantCrazyhouse) break;
\r
5387 if (x < 0 || y < 0) break;
\r
5390 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5391 SetupDropMenu(hmenu);
\r
5392 MenuPopup(hwnd, pt, hmenu, -1);
\r
5403 /* Preprocess messages for buttons in main window */
\r
5405 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5407 int id = GetWindowLong(hwnd, GWL_ID);
\r
5410 for (i=0; i<N_BUTTONS; i++) {
\r
5411 if (buttonDesc[i].id == id) break;
\r
5413 if (i == N_BUTTONS) return 0;
\r
5414 switch (message) {
\r
5419 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5420 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5427 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5430 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5431 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5432 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5433 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5435 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5437 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5438 PopUpMoveDialog((char)wParam);
\r
5444 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5447 /* Process messages for Promotion dialog box */
\r
5449 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5453 switch (message) {
\r
5454 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5455 /* Center the dialog over the application window */
\r
5456 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5457 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5458 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5459 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5460 SW_SHOW : SW_HIDE);
\r
5461 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5462 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5463 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5464 PieceToChar(WhiteAngel) != '~') ||
\r
5465 (PieceToChar(BlackAngel) >= 'A' &&
\r
5466 PieceToChar(BlackAngel) != '~') ) ?
\r
5467 SW_SHOW : SW_HIDE);
\r
5468 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5469 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5470 PieceToChar(WhiteMarshall) != '~') ||
\r
5471 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5472 PieceToChar(BlackMarshall) != '~') ) ?
\r
5473 SW_SHOW : SW_HIDE);
\r
5474 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5475 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5476 gameInfo.variant != VariantShogi ?
\r
5477 SW_SHOW : SW_HIDE);
\r
5478 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5479 gameInfo.variant != VariantShogi ?
\r
5480 SW_SHOW : SW_HIDE);
\r
5481 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5482 gameInfo.variant == VariantShogi ?
\r
5483 SW_SHOW : SW_HIDE);
\r
5484 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5485 gameInfo.variant == VariantShogi ?
\r
5486 SW_SHOW : SW_HIDE);
\r
5487 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5488 gameInfo.variant == VariantSuper ?
\r
5489 SW_SHOW : SW_HIDE);
\r
5492 case WM_COMMAND: /* message: received a command */
\r
5493 switch (LOWORD(wParam)) {
\r
5495 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5496 ClearHighlights();
\r
5497 DrawPosition(FALSE, NULL);
\r
5500 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5503 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5506 promoChar = PieceToChar(BlackRook);
\r
5509 promoChar = PieceToChar(BlackBishop);
\r
5511 case PB_Chancellor:
\r
5512 promoChar = PieceToChar(BlackMarshall);
\r
5514 case PB_Archbishop:
\r
5515 promoChar = PieceToChar(BlackAngel);
\r
5518 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5523 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5524 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5525 only show the popup when we are already sure the move is valid or
\r
5526 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5527 will figure out it is a promotion from the promoChar. */
\r
5528 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5529 if (!appData.highlightLastMove) {
\r
5530 ClearHighlights();
\r
5531 DrawPosition(FALSE, NULL);
\r
5538 /* Pop up promotion dialog */
\r
5540 PromotionPopup(HWND hwnd)
\r
5544 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5545 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5546 hwnd, (DLGPROC)lpProc);
\r
5547 FreeProcInstance(lpProc);
\r
5550 /* Toggle ShowThinking */
\r
5552 ToggleShowThinking()
\r
5554 appData.showThinking = !appData.showThinking;
\r
5555 ShowThinkingEvent();
\r
5559 LoadGameDialog(HWND hwnd, char* title)
\r
5563 char fileTitle[MSG_SIZ];
\r
5564 f = OpenFileDialog(hwnd, "rb", "",
\r
5565 appData.oldSaveStyle ? "gam" : "pgn",
\r
5567 title, &number, fileTitle, NULL);
\r
5569 cmailMsgLoaded = FALSE;
\r
5570 if (number == 0) {
\r
5571 int error = GameListBuild(f);
\r
5573 DisplayError("Cannot build game list", error);
\r
5574 } else if (!ListEmpty(&gameList) &&
\r
5575 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5576 GameListPopUp(f, fileTitle);
\r
5579 GameListDestroy();
\r
5582 LoadGame(f, number, fileTitle, FALSE);
\r
5587 ChangedConsoleFont()
\r
5590 CHARRANGE tmpsel, sel;
\r
5591 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5592 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5593 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5596 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5597 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5598 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5599 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5600 * size. This was undocumented in the version of MSVC++ that I had
\r
5601 * when I wrote the code, but is apparently documented now.
\r
5603 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5604 cfmt.bCharSet = f->lf.lfCharSet;
\r
5605 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5606 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5607 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5608 /* Why are the following seemingly needed too? */
\r
5609 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5610 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5611 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5613 tmpsel.cpMax = -1; /*999999?*/
\r
5614 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5615 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5616 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5617 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5619 paraf.cbSize = sizeof(paraf);
\r
5620 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5621 paraf.dxStartIndent = 0;
\r
5622 paraf.dxOffset = WRAP_INDENT;
\r
5623 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5624 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5627 /*---------------------------------------------------------------------------*\
\r
5629 * Window Proc for main window
\r
5631 \*---------------------------------------------------------------------------*/
\r
5633 /* Process messages for main window, etc. */
\r
5635 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5638 int wmId, wmEvent;
\r
5642 char fileTitle[MSG_SIZ];
\r
5643 char buf[MSG_SIZ];
\r
5644 static SnapData sd;
\r
5646 switch (message) {
\r
5648 case WM_PAINT: /* message: repaint portion of window */
\r
5652 case WM_ERASEBKGND:
\r
5653 if (IsIconic(hwnd)) {
\r
5654 /* Cheat; change the message */
\r
5655 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5657 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5661 case WM_LBUTTONDOWN:
\r
5662 case WM_MBUTTONDOWN:
\r
5663 case WM_RBUTTONDOWN:
\r
5664 case WM_LBUTTONUP:
\r
5665 case WM_MBUTTONUP:
\r
5666 case WM_RBUTTONUP:
\r
5667 case WM_MOUSEMOVE:
\r
5668 case WM_MOUSEWHEEL:
\r
5669 MouseEvent(hwnd, message, wParam, lParam);
\r
5672 JAWS_KB_NAVIGATION
\r
5676 JAWS_ALT_INTERCEPT
\r
5678 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5679 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5680 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5681 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5683 SendMessage(h, message, wParam, lParam);
\r
5684 } else if(lParam != KF_REPEAT) {
\r
5685 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5686 PopUpMoveDialog((char)wParam);
\r
5687 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5688 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5693 case WM_PALETTECHANGED:
\r
5694 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5696 HDC hdc = GetDC(hwndMain);
\r
5697 SelectPalette(hdc, hPal, TRUE);
\r
5698 nnew = RealizePalette(hdc);
\r
5700 paletteChanged = TRUE;
\r
5702 UpdateColors(hdc);
\r
5704 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5707 ReleaseDC(hwnd, hdc);
\r
5711 case WM_QUERYNEWPALETTE:
\r
5712 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5714 HDC hdc = GetDC(hwndMain);
\r
5715 paletteChanged = FALSE;
\r
5716 SelectPalette(hdc, hPal, FALSE);
\r
5717 nnew = RealizePalette(hdc);
\r
5719 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5721 ReleaseDC(hwnd, hdc);
\r
5726 case WM_COMMAND: /* message: command from application menu */
\r
5727 wmId = LOWORD(wParam);
\r
5728 wmEvent = HIWORD(wParam);
\r
5733 AnalysisPopDown();
\r
5734 SAY("new game enter a move to play against the computer with white");
\r
5737 case IDM_NewGameFRC:
\r
5738 if( NewGameFRC() == 0 ) {
\r
5740 AnalysisPopDown();
\r
5744 case IDM_NewVariant:
\r
5745 NewVariantPopup(hwnd);
\r
5748 case IDM_LoadGame:
\r
5749 LoadGameDialog(hwnd, "Load Game from File");
\r
5752 case IDM_LoadNextGame:
\r
5756 case IDM_LoadPrevGame:
\r
5760 case IDM_ReloadGame:
\r
5764 case IDM_LoadPosition:
\r
5765 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5766 Reset(FALSE, TRUE);
\r
5769 f = OpenFileDialog(hwnd, "rb", "",
\r
5770 appData.oldSaveStyle ? "pos" : "fen",
\r
5772 "Load Position from File", &number, fileTitle, NULL);
\r
5774 LoadPosition(f, number, fileTitle);
\r
5778 case IDM_LoadNextPosition:
\r
5779 ReloadPosition(1);
\r
5782 case IDM_LoadPrevPosition:
\r
5783 ReloadPosition(-1);
\r
5786 case IDM_ReloadPosition:
\r
5787 ReloadPosition(0);
\r
5790 case IDM_SaveGame:
\r
5791 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5792 f = OpenFileDialog(hwnd, "a", defName,
\r
5793 appData.oldSaveStyle ? "gam" : "pgn",
\r
5795 "Save Game to File", NULL, fileTitle, NULL);
\r
5797 SaveGame(f, 0, "");
\r
5801 case IDM_SavePosition:
\r
5802 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5803 f = OpenFileDialog(hwnd, "a", defName,
\r
5804 appData.oldSaveStyle ? "pos" : "fen",
\r
5806 "Save Position to File", NULL, fileTitle, NULL);
\r
5808 SavePosition(f, 0, "");
\r
5812 case IDM_SaveDiagram:
\r
5813 defName = "diagram";
\r
5814 f = OpenFileDialog(hwnd, "wb", defName,
\r
5817 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5823 case IDM_CopyGame:
\r
5824 CopyGameToClipboard();
\r
5827 case IDM_PasteGame:
\r
5828 PasteGameFromClipboard();
\r
5831 case IDM_CopyGameListToClipboard:
\r
5832 CopyGameListToClipboard();
\r
5835 /* [AS] Autodetect FEN or PGN data */
\r
5836 case IDM_PasteAny:
\r
5837 PasteGameOrFENFromClipboard();
\r
5840 /* [AS] Move history */
\r
5841 case IDM_ShowMoveHistory:
\r
5842 if( MoveHistoryIsUp() ) {
\r
5843 MoveHistoryPopDown();
\r
5846 MoveHistoryPopUp();
\r
5850 /* [AS] Eval graph */
\r
5851 case IDM_ShowEvalGraph:
\r
5852 if( EvalGraphIsUp() ) {
\r
5853 EvalGraphPopDown();
\r
5857 SetFocus(hwndMain);
\r
5861 /* [AS] Engine output */
\r
5862 case IDM_ShowEngineOutput:
\r
5863 if( EngineOutputIsUp() ) {
\r
5864 EngineOutputPopDown();
\r
5867 EngineOutputPopUp();
\r
5871 /* [AS] User adjudication */
\r
5872 case IDM_UserAdjudication_White:
\r
5873 UserAdjudicationEvent( +1 );
\r
5876 case IDM_UserAdjudication_Black:
\r
5877 UserAdjudicationEvent( -1 );
\r
5880 case IDM_UserAdjudication_Draw:
\r
5881 UserAdjudicationEvent( 0 );
\r
5884 /* [AS] Game list options dialog */
\r
5885 case IDM_GameListOptions:
\r
5886 GameListOptions();
\r
5893 case IDM_CopyPosition:
\r
5894 CopyFENToClipboard();
\r
5897 case IDM_PastePosition:
\r
5898 PasteFENFromClipboard();
\r
5901 case IDM_MailMove:
\r
5905 case IDM_ReloadCMailMsg:
\r
5906 Reset(TRUE, TRUE);
\r
5907 ReloadCmailMsgEvent(FALSE);
\r
5910 case IDM_Minimize:
\r
5911 ShowWindow(hwnd, SW_MINIMIZE);
\r
5918 case IDM_MachineWhite:
\r
5919 MachineWhiteEvent();
\r
5921 * refresh the tags dialog only if it's visible
\r
5923 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5925 tags = PGNTags(&gameInfo);
\r
5926 TagsPopUp(tags, CmailMsg());
\r
5929 SAY("computer starts playing white");
\r
5932 case IDM_MachineBlack:
\r
5933 MachineBlackEvent();
\r
5935 * refresh the tags dialog only if it's visible
\r
5937 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5939 tags = PGNTags(&gameInfo);
\r
5940 TagsPopUp(tags, CmailMsg());
\r
5943 SAY("computer starts playing black");
\r
5946 case IDM_TwoMachines:
\r
5947 TwoMachinesEvent();
\r
5949 * refresh the tags dialog only if it's visible
\r
5951 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5953 tags = PGNTags(&gameInfo);
\r
5954 TagsPopUp(tags, CmailMsg());
\r
5957 SAY("programs start playing each other");
\r
5960 case IDM_AnalysisMode:
\r
5961 if (!first.analysisSupport) {
\r
5962 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5963 DisplayError(buf, 0);
\r
5965 SAY("analyzing current position");
\r
5966 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5967 if (appData.icsActive) {
\r
5968 if (gameMode != IcsObserving) {
\r
5969 sprintf(buf, "You are not observing a game");
\r
5970 DisplayError(buf, 0);
\r
5971 /* secure check */
\r
5972 if (appData.icsEngineAnalyze) {
\r
5973 if (appData.debugMode)
\r
5974 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5975 ExitAnalyzeMode();
\r
5981 /* if enable, user want disable icsEngineAnalyze */
\r
5982 if (appData.icsEngineAnalyze) {
\r
5983 ExitAnalyzeMode();
\r
5987 appData.icsEngineAnalyze = TRUE;
\r
5988 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5991 if (!appData.showThinking) ToggleShowThinking();
\r
5992 AnalyzeModeEvent();
\r
5996 case IDM_AnalyzeFile:
\r
5997 if (!first.analysisSupport) {
\r
5998 char buf[MSG_SIZ];
\r
5999 sprintf(buf, "%s does not support analysis", first.tidy);
\r
6000 DisplayError(buf, 0);
\r
6002 if (!appData.showThinking) ToggleShowThinking();
\r
6003 AnalyzeFileEvent();
\r
6004 LoadGameDialog(hwnd, "Analyze Game from File");
\r
6005 AnalysisPeriodicEvent(1);
\r
6009 case IDM_IcsClient:
\r
6013 case IDM_EditGame:
\r
6018 case IDM_EditPosition:
\r
6019 EditPositionEvent();
\r
6020 SAY("to set up a position type a FEN");
\r
6023 case IDM_Training:
\r
6027 case IDM_ShowGameList:
\r
6028 ShowGameListProc();
\r
6031 case IDM_EditTags:
\r
6035 case IDM_EditComment:
\r
6036 if (commentDialogUp && editComment) {
\r
6039 EditCommentEvent();
\r
6059 case IDM_CallFlag:
\r
6079 case IDM_StopObserving:
\r
6080 StopObservingEvent();
\r
6083 case IDM_StopExamining:
\r
6084 StopExaminingEvent();
\r
6087 case IDM_TypeInMove:
\r
6088 PopUpMoveDialog('\000');
\r
6091 case IDM_TypeInName:
\r
6092 PopUpNameDialog('\000');
\r
6095 case IDM_Backward:
\r
6097 SetFocus(hwndMain);
\r
6104 SetFocus(hwndMain);
\r
6109 SetFocus(hwndMain);
\r
6114 SetFocus(hwndMain);
\r
6121 case IDM_TruncateGame:
\r
6122 TruncateGameEvent();
\r
6129 case IDM_RetractMove:
\r
6130 RetractMoveEvent();
\r
6133 case IDM_FlipView:
\r
6134 flipView = !flipView;
\r
6135 DrawPosition(FALSE, NULL);
\r
6138 case IDM_FlipClock:
\r
6139 flipClock = !flipClock;
\r
6140 DisplayBothClocks();
\r
6141 DrawPosition(FALSE, NULL);
\r
6144 case IDM_MuteSounds:
\r
6145 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6146 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6147 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6150 case IDM_GeneralOptions:
\r
6151 GeneralOptionsPopup(hwnd);
\r
6152 DrawPosition(TRUE, NULL);
\r
6155 case IDM_BoardOptions:
\r
6156 BoardOptionsPopup(hwnd);
\r
6159 case IDM_EnginePlayOptions:
\r
6160 EnginePlayOptionsPopup(hwnd);
\r
6163 case IDM_Engine1Options:
\r
6164 EngineOptionsPopup(hwnd, &first);
\r
6167 case IDM_Engine2Options:
\r
6168 EngineOptionsPopup(hwnd, &second);
\r
6171 case IDM_OptionsUCI:
\r
6172 UciOptionsPopup(hwnd);
\r
6175 case IDM_IcsOptions:
\r
6176 IcsOptionsPopup(hwnd);
\r
6180 FontsOptionsPopup(hwnd);
\r
6184 SoundOptionsPopup(hwnd);
\r
6187 case IDM_CommPort:
\r
6188 CommPortOptionsPopup(hwnd);
\r
6191 case IDM_LoadOptions:
\r
6192 LoadOptionsPopup(hwnd);
\r
6195 case IDM_SaveOptions:
\r
6196 SaveOptionsPopup(hwnd);
\r
6199 case IDM_TimeControl:
\r
6200 TimeControlOptionsPopup(hwnd);
\r
6203 case IDM_SaveSettings:
\r
6204 SaveSettings(settingsFileName);
\r
6207 case IDM_SaveSettingsOnExit:
\r
6208 saveSettingsOnExit = !saveSettingsOnExit;
\r
6209 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6210 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6211 MF_CHECKED : MF_UNCHECKED));
\r
6222 case IDM_AboutGame:
\r
6227 appData.debugMode = !appData.debugMode;
\r
6228 if (appData.debugMode) {
\r
6229 char dir[MSG_SIZ];
\r
6230 GetCurrentDirectory(MSG_SIZ, dir);
\r
6231 SetCurrentDirectory(installDir);
\r
6232 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6233 SetCurrentDirectory(dir);
\r
6234 setbuf(debugFP, NULL);
\r
6241 case IDM_HELPCONTENTS:
\r
6242 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6243 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6244 MessageBox (GetFocus(),
\r
6245 "Unable to activate help",
\r
6246 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6250 case IDM_HELPSEARCH:
\r
6251 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6252 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6253 MessageBox (GetFocus(),
\r
6254 "Unable to activate help",
\r
6255 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6259 case IDM_HELPHELP:
\r
6260 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6261 MessageBox (GetFocus(),
\r
6262 "Unable to activate help",
\r
6263 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6268 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6270 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6271 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6272 FreeProcInstance(lpProc);
\r
6275 case IDM_DirectCommand1:
\r
6276 AskQuestionEvent("Direct Command",
\r
6277 "Send to chess program:", "", "1");
\r
6279 case IDM_DirectCommand2:
\r
6280 AskQuestionEvent("Direct Command",
\r
6281 "Send to second chess program:", "", "2");
\r
6284 case EP_WhitePawn:
\r
6285 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6289 case EP_WhiteKnight:
\r
6290 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6294 case EP_WhiteBishop:
\r
6295 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6299 case EP_WhiteRook:
\r
6300 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6304 case EP_WhiteQueen:
\r
6305 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6309 case EP_WhiteFerz:
\r
6310 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6314 case EP_WhiteWazir:
\r
6315 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6319 case EP_WhiteAlfil:
\r
6320 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6324 case EP_WhiteCannon:
\r
6325 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6329 case EP_WhiteCardinal:
\r
6330 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6331 fromX = fromY = -1;
\r
6334 case EP_WhiteMarshall:
\r
6335 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6336 fromX = fromY = -1;
\r
6339 case EP_WhiteKing:
\r
6340 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6341 fromX = fromY = -1;
\r
6344 case EP_BlackPawn:
\r
6345 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6346 fromX = fromY = -1;
\r
6349 case EP_BlackKnight:
\r
6350 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6351 fromX = fromY = -1;
\r
6354 case EP_BlackBishop:
\r
6355 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6356 fromX = fromY = -1;
\r
6359 case EP_BlackRook:
\r
6360 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6361 fromX = fromY = -1;
\r
6364 case EP_BlackQueen:
\r
6365 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6366 fromX = fromY = -1;
\r
6369 case EP_BlackFerz:
\r
6370 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6371 fromX = fromY = -1;
\r
6374 case EP_BlackWazir:
\r
6375 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6376 fromX = fromY = -1;
\r
6379 case EP_BlackAlfil:
\r
6380 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6381 fromX = fromY = -1;
\r
6384 case EP_BlackCannon:
\r
6385 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6386 fromX = fromY = -1;
\r
6389 case EP_BlackCardinal:
\r
6390 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6391 fromX = fromY = -1;
\r
6394 case EP_BlackMarshall:
\r
6395 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6396 fromX = fromY = -1;
\r
6399 case EP_BlackKing:
\r
6400 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6401 fromX = fromY = -1;
\r
6404 case EP_EmptySquare:
\r
6405 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6406 fromX = fromY = -1;
\r
6409 case EP_ClearBoard:
\r
6410 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6411 fromX = fromY = -1;
\r
6415 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6416 fromX = fromY = -1;
\r
6420 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6421 fromX = fromY = -1;
\r
6425 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6426 fromX = fromY = -1;
\r
6430 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6431 fromX = fromY = -1;
\r
6435 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6436 fromX = fromY = -1;
\r
6440 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6441 fromX = fromY = -1;
\r
6445 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6446 fromX = fromY = -1;
\r
6450 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6451 fromX = fromY = -1;
\r
6455 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6456 fromX = fromY = -1;
\r
6460 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6466 case CLOCK_TIMER_ID:
\r
6467 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6468 clockTimerEvent = 0;
\r
6469 DecrementClocks(); /* call into back end */
\r
6471 case LOAD_GAME_TIMER_ID:
\r
6472 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6473 loadGameTimerEvent = 0;
\r
6474 AutoPlayGameLoop(); /* call into back end */
\r
6476 case ANALYSIS_TIMER_ID:
\r
6477 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6478 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6479 AnalysisPeriodicEvent(0);
\r
6481 KillTimer(hwnd, analysisTimerEvent);
\r
6482 analysisTimerEvent = 0;
\r
6485 case DELAYED_TIMER_ID:
\r
6486 KillTimer(hwnd, delayedTimerEvent);
\r
6487 delayedTimerEvent = 0;
\r
6488 delayedTimerCallback();
\r
6493 case WM_USER_Input:
\r
6494 InputEvent(hwnd, message, wParam, lParam);
\r
6497 /* [AS] Also move "attached" child windows */
\r
6498 case WM_WINDOWPOSCHANGING:
\r
6500 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6501 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6503 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6504 /* Window is moving */
\r
6507 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6508 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6509 rcMain.right = boardX + winWidth;
\r
6510 rcMain.top = boardY;
\r
6511 rcMain.bottom = boardY + winHeight;
\r
6513 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6514 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6515 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6516 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6517 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6524 /* [AS] Snapping */
\r
6525 case WM_ENTERSIZEMOVE:
\r
6526 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6527 if (hwnd == hwndMain) {
\r
6528 doingSizing = TRUE;
\r
6531 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6535 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6536 if (hwnd == hwndMain) {
\r
6537 lastSizing = wParam;
\r
6542 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6543 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6545 case WM_EXITSIZEMOVE:
\r
6546 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6547 if (hwnd == hwndMain) {
\r
6549 doingSizing = FALSE;
\r
6550 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6551 GetClientRect(hwnd, &client);
\r
6552 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6554 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6556 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6559 case WM_DESTROY: /* message: window being destroyed */
\r
6560 PostQuitMessage(0);
\r
6564 if (hwnd == hwndMain) {
\r
6569 default: /* Passes it on if unprocessed */
\r
6570 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6575 /*---------------------------------------------------------------------------*\
\r
6577 * Misc utility routines
\r
6579 \*---------------------------------------------------------------------------*/
\r
6582 * Decent random number generator, at least not as bad as Windows
\r
6583 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6585 unsigned int randstate;
\r
6590 randstate = randstate * 1664525 + 1013904223;
\r
6591 return (int) randstate & 0x7fffffff;
\r
6595 mysrandom(unsigned int seed)
\r
6602 * returns TRUE if user selects a different color, FALSE otherwise
\r
6606 ChangeColor(HWND hwnd, COLORREF *which)
\r
6608 static BOOL firstTime = TRUE;
\r
6609 static DWORD customColors[16];
\r
6611 COLORREF newcolor;
\r
6616 /* Make initial colors in use available as custom colors */
\r
6617 /* Should we put the compiled-in defaults here instead? */
\r
6619 customColors[i++] = lightSquareColor & 0xffffff;
\r
6620 customColors[i++] = darkSquareColor & 0xffffff;
\r
6621 customColors[i++] = whitePieceColor & 0xffffff;
\r
6622 customColors[i++] = blackPieceColor & 0xffffff;
\r
6623 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6624 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6626 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6627 customColors[i++] = textAttribs[ccl].color;
\r
6629 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6630 firstTime = FALSE;
\r
6633 cc.lStructSize = sizeof(cc);
\r
6634 cc.hwndOwner = hwnd;
\r
6635 cc.hInstance = NULL;
\r
6636 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6637 cc.lpCustColors = (LPDWORD) customColors;
\r
6638 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6640 if (!ChooseColor(&cc)) return FALSE;
\r
6642 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6643 if (newcolor == *which) return FALSE;
\r
6644 *which = newcolor;
\r
6648 InitDrawingColors();
\r
6649 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6654 MyLoadSound(MySound *ms)
\r
6660 if (ms->data) free(ms->data);
\r
6663 switch (ms->name[0]) {
\r
6669 /* System sound from Control Panel. Don't preload here. */
\r
6673 if (ms->name[1] == NULLCHAR) {
\r
6674 /* "!" alone = silence */
\r
6677 /* Builtin wave resource. Error if not found. */
\r
6678 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6679 if (h == NULL) break;
\r
6680 ms->data = (void *)LoadResource(hInst, h);
\r
6681 if (h == NULL) break;
\r
6686 /* .wav file. Error if not found. */
\r
6687 f = fopen(ms->name, "rb");
\r
6688 if (f == NULL) break;
\r
6689 if (fstat(fileno(f), &st) < 0) break;
\r
6690 ms->data = malloc(st.st_size);
\r
6691 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6697 char buf[MSG_SIZ];
\r
6698 sprintf(buf, "Error loading sound %s", ms->name);
\r
6699 DisplayError(buf, GetLastError());
\r
6705 MyPlaySound(MySound *ms)
\r
6707 BOOLEAN ok = FALSE;
\r
6709 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6710 switch (ms->name[0]) {
\r
6712 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6717 /* System sound from Control Panel (deprecated feature).
\r
6718 "$" alone or an unset sound name gets default beep (still in use). */
\r
6719 if (ms->name[1]) {
\r
6720 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6722 if (!ok) ok = MessageBeep(MB_OK);
\r
6725 /* Builtin wave resource, or "!" alone for silence */
\r
6726 if (ms->name[1]) {
\r
6727 if (ms->data == NULL) return FALSE;
\r
6728 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6734 /* .wav file. Error if not found. */
\r
6735 if (ms->data == NULL) return FALSE;
\r
6736 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6739 /* Don't print an error: this can happen innocently if the sound driver
\r
6740 is busy; for instance, if another instance of WinBoard is playing
\r
6741 a sound at about the same time. */
\r
6744 char buf[MSG_SIZ];
\r
6745 sprintf(buf, "Error playing sound %s", ms->name);
\r
6746 DisplayError(buf, GetLastError());
\r
6754 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6757 OPENFILENAME *ofn;
\r
6758 static UINT *number; /* gross that this is static */
\r
6760 switch (message) {
\r
6761 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6762 /* Center the dialog over the application window */
\r
6763 ofn = (OPENFILENAME *) lParam;
\r
6764 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6765 number = (UINT *) ofn->lCustData;
\r
6766 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6770 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6771 return FALSE; /* Allow for further processing */
\r
6774 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6775 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6777 return FALSE; /* Allow for further processing */
\r
6783 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6785 static UINT *number;
\r
6786 OPENFILENAME *ofname;
\r
6789 case WM_INITDIALOG:
\r
6790 ofname = (OPENFILENAME *)lParam;
\r
6791 number = (UINT *)(ofname->lCustData);
\r
6794 ofnot = (OFNOTIFY *)lParam;
\r
6795 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6796 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6805 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6806 char *nameFilt, char *dlgTitle, UINT *number,
\r
6807 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6809 OPENFILENAME openFileName;
\r
6810 char buf1[MSG_SIZ];
\r
6813 if (fileName == NULL) fileName = buf1;
\r
6814 if (defName == NULL) {
\r
6815 strcpy(fileName, "*.");
\r
6816 strcat(fileName, defExt);
\r
6818 strcpy(fileName, defName);
\r
6820 if (fileTitle) strcpy(fileTitle, "");
\r
6821 if (number) *number = 0;
\r
6823 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6824 openFileName.hwndOwner = hwnd;
\r
6825 openFileName.hInstance = (HANDLE) hInst;
\r
6826 openFileName.lpstrFilter = nameFilt;
\r
6827 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6828 openFileName.nMaxCustFilter = 0L;
\r
6829 openFileName.nFilterIndex = 1L;
\r
6830 openFileName.lpstrFile = fileName;
\r
6831 openFileName.nMaxFile = MSG_SIZ;
\r
6832 openFileName.lpstrFileTitle = fileTitle;
\r
6833 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6834 openFileName.lpstrInitialDir = NULL;
\r
6835 openFileName.lpstrTitle = dlgTitle;
\r
6836 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6837 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6838 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6839 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6840 openFileName.nFileOffset = 0;
\r
6841 openFileName.nFileExtension = 0;
\r
6842 openFileName.lpstrDefExt = defExt;
\r
6843 openFileName.lCustData = (LONG) number;
\r
6844 openFileName.lpfnHook = oldDialog ?
\r
6845 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6846 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6848 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6849 GetOpenFileName(&openFileName)) {
\r
6850 /* open the file */
\r
6851 f = fopen(openFileName.lpstrFile, write);
\r
6853 MessageBox(hwnd, "File open failed", NULL,
\r
6854 MB_OK|MB_ICONEXCLAMATION);
\r
6858 int err = CommDlgExtendedError();
\r
6859 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6868 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6870 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6873 * Get the first pop-up menu in the menu template. This is the
\r
6874 * menu that TrackPopupMenu displays.
\r
6876 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6878 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6881 * TrackPopup uses screen coordinates, so convert the
\r
6882 * coordinates of the mouse click to screen coordinates.
\r
6884 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6886 /* Draw and track the floating pop-up menu. */
\r
6887 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6888 pt.x, pt.y, 0, hwnd, NULL);
\r
6890 /* Destroy the menu.*/
\r
6891 DestroyMenu(hmenu);
\r
6896 int sizeX, sizeY, newSizeX, newSizeY;
\r
6898 } ResizeEditPlusButtonsClosure;
\r
6901 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6903 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6907 if (hChild == cl->hText) return TRUE;
\r
6908 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6909 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6910 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6911 ScreenToClient(cl->hDlg, &pt);
\r
6912 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6913 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6917 /* Resize a dialog that has a (rich) edit field filling most of
\r
6918 the top, with a row of buttons below */
\r
6920 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6923 int newTextHeight, newTextWidth;
\r
6924 ResizeEditPlusButtonsClosure cl;
\r
6926 /*if (IsIconic(hDlg)) return;*/
\r
6927 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6929 cl.hdwp = BeginDeferWindowPos(8);
\r
6931 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6932 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6933 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6934 if (newTextHeight < 0) {
\r
6935 newSizeY += -newTextHeight;
\r
6936 newTextHeight = 0;
\r
6938 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6939 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6945 cl.newSizeX = newSizeX;
\r
6946 cl.newSizeY = newSizeY;
\r
6947 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6949 EndDeferWindowPos(cl.hdwp);
\r
6952 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6954 RECT rChild, rParent;
\r
6955 int wChild, hChild, wParent, hParent;
\r
6956 int wScreen, hScreen, xNew, yNew;
\r
6959 /* Get the Height and Width of the child window */
\r
6960 GetWindowRect (hwndChild, &rChild);
\r
6961 wChild = rChild.right - rChild.left;
\r
6962 hChild = rChild.bottom - rChild.top;
\r
6964 /* Get the Height and Width of the parent window */
\r
6965 GetWindowRect (hwndParent, &rParent);
\r
6966 wParent = rParent.right - rParent.left;
\r
6967 hParent = rParent.bottom - rParent.top;
\r
6969 /* Get the display limits */
\r
6970 hdc = GetDC (hwndChild);
\r
6971 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6972 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6973 ReleaseDC(hwndChild, hdc);
\r
6975 /* Calculate new X position, then adjust for screen */
\r
6976 xNew = rParent.left + ((wParent - wChild) /2);
\r
6979 } else if ((xNew+wChild) > wScreen) {
\r
6980 xNew = wScreen - wChild;
\r
6983 /* Calculate new Y position, then adjust for screen */
\r
6985 yNew = rParent.top + ((hParent - hChild) /2);
\r
6988 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6993 } else if ((yNew+hChild) > hScreen) {
\r
6994 yNew = hScreen - hChild;
\r
6997 /* Set it, and return */
\r
6998 return SetWindowPos (hwndChild, NULL,
\r
6999 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
7002 /* Center one window over another */
\r
7003 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
7005 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
7008 /*---------------------------------------------------------------------------*\
\r
7010 * Startup Dialog functions
\r
7012 \*---------------------------------------------------------------------------*/
\r
7014 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7016 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7018 while (*cd != NULL) {
\r
7019 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7025 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7027 char buf1[ARG_MAX];
\r
7030 if (str[0] == '@') {
\r
7031 FILE* f = fopen(str + 1, "r");
\r
7033 DisplayFatalError(str + 1, errno, 2);
\r
7036 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7038 buf1[len] = NULLCHAR;
\r
7042 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7045 char buf[MSG_SIZ];
\r
7046 char *end = strchr(str, '\n');
\r
7047 if (end == NULL) return;
\r
7048 memcpy(buf, str, end - str);
\r
7049 buf[end - str] = NULLCHAR;
\r
7050 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7056 SetStartupDialogEnables(HWND hDlg)
\r
7058 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7059 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7060 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7061 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7062 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7063 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7064 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7065 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7066 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7067 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7068 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7069 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7070 IsDlgButtonChecked(hDlg, OPT_View));
\r
7074 QuoteForFilename(char *filename)
\r
7076 int dquote, space;
\r
7077 dquote = strchr(filename, '"') != NULL;
\r
7078 space = strchr(filename, ' ') != NULL;
\r
7079 if (dquote || space) {
\r
7091 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7093 char buf[MSG_SIZ];
\r
7096 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7097 q = QuoteForFilename(nthcp);
\r
7098 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7099 if (*nthdir != NULLCHAR) {
\r
7100 q = QuoteForFilename(nthdir);
\r
7101 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7103 if (*nthcp == NULLCHAR) {
\r
7104 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7105 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7106 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7107 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7112 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7114 char buf[MSG_SIZ];
\r
7118 switch (message) {
\r
7119 case WM_INITDIALOG:
\r
7120 /* Center the dialog */
\r
7121 CenterWindow (hDlg, GetDesktopWindow());
\r
7122 /* Initialize the dialog items */
\r
7123 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7124 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7125 firstChessProgramNames);
\r
7126 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7127 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7128 secondChessProgramNames);
\r
7129 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7130 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7131 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7132 if (*appData.icsHelper != NULLCHAR) {
\r
7133 char *q = QuoteForFilename(appData.icsHelper);
\r
7134 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7136 if (*appData.icsHost == NULLCHAR) {
\r
7137 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7138 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7139 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7140 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7141 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7144 if (appData.icsActive) {
\r
7145 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7147 else if (appData.noChessProgram) {
\r
7148 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7151 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7154 SetStartupDialogEnables(hDlg);
\r
7158 switch (LOWORD(wParam)) {
\r
7160 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7161 strcpy(buf, "/fcp=");
\r
7162 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7164 ParseArgs(StringGet, &p);
\r
7165 strcpy(buf, "/scp=");
\r
7166 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7168 ParseArgs(StringGet, &p);
\r
7169 appData.noChessProgram = FALSE;
\r
7170 appData.icsActive = FALSE;
\r
7171 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7172 strcpy(buf, "/ics /icshost=");
\r
7173 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7175 ParseArgs(StringGet, &p);
\r
7176 if (appData.zippyPlay) {
\r
7177 strcpy(buf, "/fcp=");
\r
7178 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7180 ParseArgs(StringGet, &p);
\r
7182 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7183 appData.noChessProgram = TRUE;
\r
7184 appData.icsActive = FALSE;
\r
7186 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7187 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7190 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7191 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7193 ParseArgs(StringGet, &p);
\r
7195 EndDialog(hDlg, TRUE);
\r
7202 case IDM_HELPCONTENTS:
\r
7203 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7204 MessageBox (GetFocus(),
\r
7205 "Unable to activate help",
\r
7206 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7211 SetStartupDialogEnables(hDlg);
\r
7219 /*---------------------------------------------------------------------------*\
\r
7221 * About box dialog functions
\r
7223 \*---------------------------------------------------------------------------*/
\r
7225 /* Process messages for "About" dialog box */
\r
7227 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7229 switch (message) {
\r
7230 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7231 /* Center the dialog over the application window */
\r
7232 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7233 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7237 case WM_COMMAND: /* message: received a command */
\r
7238 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7239 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7240 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7248 /*---------------------------------------------------------------------------*\
\r
7250 * Comment Dialog functions
\r
7252 \*---------------------------------------------------------------------------*/
\r
7255 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7257 static HANDLE hwndText = NULL;
\r
7258 int len, newSizeX, newSizeY, flags;
\r
7259 static int sizeX, sizeY;
\r
7264 switch (message) {
\r
7265 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7266 /* Initialize the dialog items */
\r
7267 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7268 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7269 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7270 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7271 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7272 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7273 SetWindowText(hDlg, commentTitle);
\r
7274 if (editComment) {
\r
7275 SetFocus(hwndText);
\r
7277 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7279 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7280 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7281 MAKELPARAM(FALSE, 0));
\r
7282 /* Size and position the dialog */
\r
7283 if (!commentDialog) {
\r
7284 commentDialog = hDlg;
\r
7285 flags = SWP_NOZORDER;
\r
7286 GetClientRect(hDlg, &rect);
\r
7287 sizeX = rect.right;
\r
7288 sizeY = rect.bottom;
\r
7289 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7290 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7291 WINDOWPLACEMENT wp;
\r
7292 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7293 wp.length = sizeof(WINDOWPLACEMENT);
\r
7295 wp.showCmd = SW_SHOW;
\r
7296 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7297 wp.rcNormalPosition.left = commentX;
\r
7298 wp.rcNormalPosition.right = commentX + commentW;
\r
7299 wp.rcNormalPosition.top = commentY;
\r
7300 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7301 SetWindowPlacement(hDlg, &wp);
\r
7303 GetClientRect(hDlg, &rect);
\r
7304 newSizeX = rect.right;
\r
7305 newSizeY = rect.bottom;
\r
7306 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7307 newSizeX, newSizeY);
\r
7314 case WM_COMMAND: /* message: received a command */
\r
7315 switch (LOWORD(wParam)) {
\r
7317 if (editComment) {
\r
7319 /* Read changed options from the dialog box */
\r
7320 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7321 len = GetWindowTextLength(hwndText);
\r
7322 str = (char *) malloc(len + 1);
\r
7323 GetWindowText(hwndText, str, len + 1);
\r
7332 ReplaceComment(commentIndex, str);
\r
7339 case OPT_CancelComment:
\r
7343 case OPT_ClearComment:
\r
7344 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7347 case OPT_EditComment:
\r
7348 EditCommentEvent();
\r
7357 newSizeX = LOWORD(lParam);
\r
7358 newSizeY = HIWORD(lParam);
\r
7359 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7364 case WM_GETMINMAXINFO:
\r
7365 /* Prevent resizing window too small */
\r
7366 mmi = (MINMAXINFO *) lParam;
\r
7367 mmi->ptMinTrackSize.x = 100;
\r
7368 mmi->ptMinTrackSize.y = 100;
\r
7375 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7380 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7382 if (str == NULL) str = "";
\r
7383 p = (char *) malloc(2 * strlen(str) + 2);
\r
7386 if (*str == '\n') *q++ = '\r';
\r
7390 if (commentText != NULL) free(commentText);
\r
7392 commentIndex = index;
\r
7393 commentTitle = title;
\r
7395 editComment = edit;
\r
7397 if (commentDialog) {
\r
7398 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7399 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7401 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7402 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7403 hwndMain, (DLGPROC)lpProc);
\r
7404 FreeProcInstance(lpProc);
\r
7406 commentDialogUp = TRUE;
\r
7410 /*---------------------------------------------------------------------------*\
\r
7412 * Type-in move dialog functions
\r
7414 \*---------------------------------------------------------------------------*/
\r
7417 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7419 char move[MSG_SIZ];
\r
7421 ChessMove moveType;
\r
7422 int fromX, fromY, toX, toY;
\r
7425 switch (message) {
\r
7426 case WM_INITDIALOG:
\r
7427 move[0] = (char) lParam;
\r
7428 move[1] = NULLCHAR;
\r
7429 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7430 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7431 SetWindowText(hInput, move);
\r
7433 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7437 switch (LOWORD(wParam)) {
\r
7439 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7440 { int n; Board board;
\r
7442 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7443 EditPositionPasteFEN(move);
\r
7444 EndDialog(hDlg, TRUE);
\r
7447 // [HGM] movenum: allow move number to be typed in any mode
\r
7448 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7449 currentMove = 2*n-1;
\r
7450 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7451 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7452 EndDialog(hDlg, TRUE);
\r
7453 DrawPosition(TRUE, boards[currentMove]);
\r
7454 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7455 else DisplayMessage("", "");
\r
7459 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7460 gameMode != Training) {
\r
7461 DisplayMoveError("Displayed move is not current");
\r
7463 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7464 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7465 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7466 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7467 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7468 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7469 if (gameMode != Training)
\r
7470 forwardMostMove = currentMove;
\r
7471 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7473 DisplayMoveError("Could not parse move");
\r
7476 EndDialog(hDlg, TRUE);
\r
7479 EndDialog(hDlg, FALSE);
\r
7490 PopUpMoveDialog(char firstchar)
\r
7494 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7495 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7496 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7497 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7498 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7499 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7500 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7501 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7502 gameMode == Training) {
\r
7503 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7504 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7505 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7506 FreeProcInstance(lpProc);
\r
7510 /*---------------------------------------------------------------------------*\
\r
7512 * Type-in name dialog functions
\r
7514 \*---------------------------------------------------------------------------*/
\r
7517 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7519 char move[MSG_SIZ];
\r
7522 switch (message) {
\r
7523 case WM_INITDIALOG:
\r
7524 move[0] = (char) lParam;
\r
7525 move[1] = NULLCHAR;
\r
7526 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7527 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7528 SetWindowText(hInput, move);
\r
7530 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7534 switch (LOWORD(wParam)) {
\r
7536 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7537 appData.userName = strdup(move);
\r
7540 EndDialog(hDlg, TRUE);
\r
7543 EndDialog(hDlg, FALSE);
\r
7554 PopUpNameDialog(char firstchar)
\r
7558 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7559 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7560 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7561 FreeProcInstance(lpProc);
\r
7564 /*---------------------------------------------------------------------------*\
\r
7568 \*---------------------------------------------------------------------------*/
\r
7570 /* Nonmodal error box */
\r
7571 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7572 WPARAM wParam, LPARAM lParam);
\r
7575 ErrorPopUp(char *title, char *content)
\r
7579 BOOLEAN modal = hwndMain == NULL;
\r
7597 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7598 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7601 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7603 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7604 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7605 hwndMain, (DLGPROC)lpProc);
\r
7606 FreeProcInstance(lpProc);
\r
7613 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7614 if (errorDialog == NULL) return;
\r
7615 DestroyWindow(errorDialog);
\r
7616 errorDialog = NULL;
\r
7620 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7625 switch (message) {
\r
7626 case WM_INITDIALOG:
\r
7627 GetWindowRect(hDlg, &rChild);
\r
7630 SetWindowPos(hDlg, NULL, rChild.left,
\r
7631 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7632 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7636 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7637 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7638 and it doesn't work when you resize the dialog.
\r
7639 For now, just give it a default position.
\r
7641 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7643 errorDialog = hDlg;
\r
7644 SetWindowText(hDlg, errorTitle);
\r
7645 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7646 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7650 switch (LOWORD(wParam)) {
\r
7653 if (errorDialog == hDlg) errorDialog = NULL;
\r
7654 DestroyWindow(hDlg);
\r
7666 HWND gothicDialog = NULL;
\r
7669 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7673 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7675 switch (message) {
\r
7676 case WM_INITDIALOG:
\r
7677 GetWindowRect(hDlg, &rChild);
\r
7679 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7683 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7684 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7685 and it doesn't work when you resize the dialog.
\r
7686 For now, just give it a default position.
\r
7688 gothicDialog = hDlg;
\r
7689 SetWindowText(hDlg, errorTitle);
\r
7690 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7691 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7695 switch (LOWORD(wParam)) {
\r
7698 if (errorDialog == hDlg) errorDialog = NULL;
\r
7699 DestroyWindow(hDlg);
\r
7711 GothicPopUp(char *title, VariantClass variant)
\r
7714 static char *lastTitle;
\r
7716 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7717 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7719 if(lastTitle != title && gothicDialog != NULL) {
\r
7720 DestroyWindow(gothicDialog);
\r
7721 gothicDialog = NULL;
\r
7723 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7724 title = lastTitle;
\r
7725 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7726 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7727 hwndMain, (DLGPROC)lpProc);
\r
7728 FreeProcInstance(lpProc);
\r
7733 /*---------------------------------------------------------------------------*\
\r
7735 * Ics Interaction console functions
\r
7737 \*---------------------------------------------------------------------------*/
\r
7739 #define HISTORY_SIZE 64
\r
7740 static char *history[HISTORY_SIZE];
\r
7741 int histIn = 0, histP = 0;
\r
7744 SaveInHistory(char *cmd)
\r
7746 if (history[histIn] != NULL) {
\r
7747 free(history[histIn]);
\r
7748 history[histIn] = NULL;
\r
7750 if (*cmd == NULLCHAR) return;
\r
7751 history[histIn] = StrSave(cmd);
\r
7752 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7753 if (history[histIn] != NULL) {
\r
7754 free(history[histIn]);
\r
7755 history[histIn] = NULL;
\r
7761 PrevInHistory(char *cmd)
\r
7764 if (histP == histIn) {
\r
7765 if (history[histIn] != NULL) free(history[histIn]);
\r
7766 history[histIn] = StrSave(cmd);
\r
7768 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7769 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7771 return history[histP];
\r
7777 if (histP == histIn) return NULL;
\r
7778 histP = (histP + 1) % HISTORY_SIZE;
\r
7779 return history[histP];
\r
7786 BOOLEAN immediate;
\r
7787 } IcsTextMenuEntry;
\r
7788 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7789 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7792 ParseIcsTextMenu(char *icsTextMenuString)
\r
7795 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7796 char *p = icsTextMenuString;
\r
7797 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7800 if (e->command != NULL) {
\r
7802 e->command = NULL;
\r
7806 e = icsTextMenuEntry;
\r
7807 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7808 if (*p == ';' || *p == '\n') {
\r
7809 e->item = strdup("-");
\r
7810 e->command = NULL;
\r
7812 } else if (*p == '-') {
\r
7813 e->item = strdup("-");
\r
7814 e->command = NULL;
\r
7818 char *q, *r, *s, *t;
\r
7820 q = strchr(p, ',');
\r
7821 if (q == NULL) break;
\r
7823 r = strchr(q + 1, ',');
\r
7824 if (r == NULL) break;
\r
7826 s = strchr(r + 1, ',');
\r
7827 if (s == NULL) break;
\r
7830 t = strchr(s + 1, c);
\r
7833 t = strchr(s + 1, c);
\r
7835 if (t != NULL) *t = NULLCHAR;
\r
7836 e->item = strdup(p);
\r
7837 e->command = strdup(q + 1);
\r
7838 e->getname = *(r + 1) != '0';
\r
7839 e->immediate = *(s + 1) != '0';
\r
7843 if (t == NULL) break;
\r
7852 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7856 hmenu = LoadMenu(hInst, "TextMenu");
\r
7857 h = GetSubMenu(hmenu, 0);
\r
7859 if (strcmp(e->item, "-") == 0) {
\r
7860 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7862 if (e->item[0] == '|') {
\r
7863 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7864 IDM_CommandX + i, &e->item[1]);
\r
7866 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7875 WNDPROC consoleTextWindowProc;
\r
7878 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7880 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7881 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7885 SetWindowText(hInput, command);
\r
7887 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7889 sel.cpMin = 999999;
\r
7890 sel.cpMax = 999999;
\r
7891 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7896 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7897 if (sel.cpMin == sel.cpMax) {
\r
7898 /* Expand to surrounding word */
\r
7901 tr.chrg.cpMax = sel.cpMin;
\r
7902 tr.chrg.cpMin = --sel.cpMin;
\r
7903 if (sel.cpMin < 0) break;
\r
7904 tr.lpstrText = name;
\r
7905 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7906 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7910 tr.chrg.cpMin = sel.cpMax;
\r
7911 tr.chrg.cpMax = ++sel.cpMax;
\r
7912 tr.lpstrText = name;
\r
7913 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7914 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7917 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7918 MessageBeep(MB_ICONEXCLAMATION);
\r
7922 tr.lpstrText = name;
\r
7923 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7925 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7926 MessageBeep(MB_ICONEXCLAMATION);
\r
7929 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7932 sprintf(buf, "%s %s", command, name);
\r
7933 SetWindowText(hInput, buf);
\r
7934 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7936 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7937 SetWindowText(hInput, buf);
\r
7938 sel.cpMin = 999999;
\r
7939 sel.cpMax = 999999;
\r
7940 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7946 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7951 switch (message) {
\r
7953 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7956 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7959 sel.cpMin = 999999;
\r
7960 sel.cpMax = 999999;
\r
7961 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7962 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7967 if(wParam != '\022') {
\r
7968 if (wParam == '\t') {
\r
7969 if (GetKeyState(VK_SHIFT) < 0) {
\r
7971 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7972 if (buttonDesc[0].hwnd) {
\r
7973 SetFocus(buttonDesc[0].hwnd);
\r
7975 SetFocus(hwndMain);
\r
7979 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7982 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7983 JAWS_DELETE( SetFocus(hInput); )
\r
7984 SendMessage(hInput, message, wParam, lParam);
\r
7987 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7988 case WM_RBUTTONUP:
\r
7989 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7990 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7991 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7994 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7995 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7996 if (sel.cpMin == sel.cpMax) {
\r
7997 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7998 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
8000 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8001 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8003 pt.x = LOWORD(lParam);
\r
8004 pt.y = HIWORD(lParam);
\r
8005 MenuPopup(hwnd, pt, hmenu, -1);
\r
8009 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8011 return SendMessage(hInput, message, wParam, lParam);
\r
8012 case WM_MBUTTONDOWN:
\r
8013 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8014 case WM_RBUTTONDOWN:
\r
8015 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8016 /* Move selection here if it was empty */
\r
8018 pt.x = LOWORD(lParam);
\r
8019 pt.y = HIWORD(lParam);
\r
8020 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8021 if (sel.cpMin == sel.cpMax) {
\r
8022 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8023 sel.cpMax = sel.cpMin;
\r
8024 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8026 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8030 switch (LOWORD(wParam)) {
\r
8031 case IDM_QuickPaste:
\r
8033 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8034 if (sel.cpMin == sel.cpMax) {
\r
8035 MessageBeep(MB_ICONEXCLAMATION);
\r
8038 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8039 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8040 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8045 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8048 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8051 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8055 int i = LOWORD(wParam) - IDM_CommandX;
\r
8056 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8057 icsTextMenuEntry[i].command != NULL) {
\r
8058 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8059 icsTextMenuEntry[i].getname,
\r
8060 icsTextMenuEntry[i].immediate);
\r
8068 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8071 WNDPROC consoleInputWindowProc;
\r
8074 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8076 char buf[MSG_SIZ];
\r
8078 static BOOL sendNextChar = FALSE;
\r
8079 static BOOL quoteNextChar = FALSE;
\r
8080 InputSource *is = consoleInputSource;
\r
8084 switch (message) {
\r
8086 if (!appData.localLineEditing || sendNextChar) {
\r
8087 is->buf[0] = (CHAR) wParam;
\r
8089 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8090 sendNextChar = FALSE;
\r
8093 if (quoteNextChar) {
\r
8094 buf[0] = (char) wParam;
\r
8095 buf[1] = NULLCHAR;
\r
8096 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8097 quoteNextChar = FALSE;
\r
8101 case '\r': /* Enter key */
\r
8102 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8103 if (consoleEcho) SaveInHistory(is->buf);
\r
8104 is->buf[is->count++] = '\n';
\r
8105 is->buf[is->count] = NULLCHAR;
\r
8106 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8107 if (consoleEcho) {
\r
8108 ConsoleOutput(is->buf, is->count, TRUE);
\r
8109 } else if (appData.localLineEditing) {
\r
8110 ConsoleOutput("\n", 1, TRUE);
\r
8113 case '\033': /* Escape key */
\r
8114 SetWindowText(hwnd, "");
\r
8115 cf.cbSize = sizeof(CHARFORMAT);
\r
8116 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8117 if (consoleEcho) {
\r
8118 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8120 cf.crTextColor = COLOR_ECHOOFF;
\r
8122 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8123 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8125 case '\t': /* Tab key */
\r
8126 if (GetKeyState(VK_SHIFT) < 0) {
\r
8128 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8131 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8132 if (buttonDesc[0].hwnd) {
\r
8133 SetFocus(buttonDesc[0].hwnd);
\r
8135 SetFocus(hwndMain);
\r
8139 case '\023': /* Ctrl+S */
\r
8140 sendNextChar = TRUE;
\r
8142 case '\021': /* Ctrl+Q */
\r
8143 quoteNextChar = TRUE;
\r
8153 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8154 p = PrevInHistory(buf);
\r
8156 SetWindowText(hwnd, p);
\r
8157 sel.cpMin = 999999;
\r
8158 sel.cpMax = 999999;
\r
8159 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8164 p = NextInHistory();
\r
8166 SetWindowText(hwnd, p);
\r
8167 sel.cpMin = 999999;
\r
8168 sel.cpMax = 999999;
\r
8169 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8175 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8179 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8183 case WM_MBUTTONDOWN:
\r
8184 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8185 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8187 case WM_RBUTTONUP:
\r
8188 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8189 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8190 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8194 hmenu = LoadMenu(hInst, "InputMenu");
\r
8195 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8196 if (sel.cpMin == sel.cpMax) {
\r
8197 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8198 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8200 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8201 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8203 pt.x = LOWORD(lParam);
\r
8204 pt.y = HIWORD(lParam);
\r
8205 MenuPopup(hwnd, pt, hmenu, -1);
\r
8209 switch (LOWORD(wParam)) {
\r
8211 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8213 case IDM_SelectAll:
\r
8215 sel.cpMax = -1; /*999999?*/
\r
8216 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8219 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8222 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8225 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8230 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8233 #define CO_MAX 100000
\r
8234 #define CO_TRIM 1000
\r
8237 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8239 static SnapData sd;
\r
8240 static HWND hText, hInput /*, hFocus*/;
\r
8241 // InputSource *is = consoleInputSource;
\r
8243 static int sizeX, sizeY;
\r
8244 int newSizeX, newSizeY;
\r
8247 switch (message) {
\r
8249 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8251 ENLINK *pLink = (ENLINK*)lParam;
\r
8252 if (pLink->msg == WM_LBUTTONUP)
\r
8256 tr.chrg = pLink->chrg;
\r
8257 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8258 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8259 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8260 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8261 free(tr.lpstrText);
\r
8265 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8266 hwndConsole = hDlg;
\r
8267 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8268 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8270 consoleTextWindowProc = (WNDPROC)
\r
8271 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8272 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8273 consoleInputWindowProc = (WNDPROC)
\r
8274 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8275 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8276 Colorize(ColorNormal, TRUE);
\r
8277 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8278 ChangedConsoleFont();
\r
8279 GetClientRect(hDlg, &rect);
\r
8280 sizeX = rect.right;
\r
8281 sizeY = rect.bottom;
\r
8282 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8283 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8284 WINDOWPLACEMENT wp;
\r
8285 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8286 wp.length = sizeof(WINDOWPLACEMENT);
\r
8288 wp.showCmd = SW_SHOW;
\r
8289 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8290 wp.rcNormalPosition.left = wpConsole.x;
\r
8291 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8292 wp.rcNormalPosition.top = wpConsole.y;
\r
8293 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8294 SetWindowPlacement(hDlg, &wp);
\r
8297 // [HGM] Chessknight's change 2004-07-13
\r
8298 else { /* Determine Defaults */
\r
8299 WINDOWPLACEMENT wp;
\r
8300 wpConsole.x = winWidth + 1;
\r
8301 wpConsole.y = boardY;
\r
8302 wpConsole.width = screenWidth - winWidth;
\r
8303 wpConsole.height = winHeight;
\r
8304 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8305 wp.length = sizeof(WINDOWPLACEMENT);
\r
8307 wp.showCmd = SW_SHOW;
\r
8308 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8309 wp.rcNormalPosition.left = wpConsole.x;
\r
8310 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8311 wp.rcNormalPosition.top = wpConsole.y;
\r
8312 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8313 SetWindowPlacement(hDlg, &wp);
\r
8328 if (IsIconic(hDlg)) break;
\r
8329 newSizeX = LOWORD(lParam);
\r
8330 newSizeY = HIWORD(lParam);
\r
8331 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8332 RECT rectText, rectInput;
\r
8334 int newTextHeight, newTextWidth;
\r
8335 GetWindowRect(hText, &rectText);
\r
8336 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8337 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8338 if (newTextHeight < 0) {
\r
8339 newSizeY += -newTextHeight;
\r
8340 newTextHeight = 0;
\r
8342 SetWindowPos(hText, NULL, 0, 0,
\r
8343 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8344 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8345 pt.x = rectInput.left;
\r
8346 pt.y = rectInput.top + newSizeY - sizeY;
\r
8347 ScreenToClient(hDlg, &pt);
\r
8348 SetWindowPos(hInput, NULL,
\r
8349 pt.x, pt.y, /* needs client coords */
\r
8350 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8351 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8357 case WM_GETMINMAXINFO:
\r
8358 /* Prevent resizing window too small */
\r
8359 mmi = (MINMAXINFO *) lParam;
\r
8360 mmi->ptMinTrackSize.x = 100;
\r
8361 mmi->ptMinTrackSize.y = 100;
\r
8364 /* [AS] Snapping */
\r
8365 case WM_ENTERSIZEMOVE:
\r
8366 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8369 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8372 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8374 case WM_EXITSIZEMOVE:
\r
8375 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8378 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8385 HWND hCons, hText;
\r
8387 if (hwndConsole) return;
\r
8388 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8389 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8391 // make the text item in the console do URL links
\r
8392 hText = GetDlgItem(hCons, OPT_ConsoleText);
\r
8393 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8394 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8395 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8400 ConsoleOutput(char* data, int length, int forceVisible)
\r
8405 char buf[CO_MAX+1];
\r
8408 static int delayLF = 0;
\r
8409 CHARRANGE savesel, sel;
\r
8411 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8419 while (length--) {
\r
8427 } else if (*p == '\007') {
\r
8428 MyPlaySound(&sounds[(int)SoundBell]);
\r
8435 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8436 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8437 /* Save current selection */
\r
8438 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8439 exlen = GetWindowTextLength(hText);
\r
8440 /* Find out whether current end of text is visible */
\r
8441 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8442 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8443 /* Trim existing text if it's too long */
\r
8444 if (exlen + (q - buf) > CO_MAX) {
\r
8445 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8448 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8449 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8451 savesel.cpMin -= trim;
\r
8452 savesel.cpMax -= trim;
\r
8453 if (exlen < 0) exlen = 0;
\r
8454 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8455 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8457 /* Append the new text */
\r
8458 sel.cpMin = exlen;
\r
8459 sel.cpMax = exlen;
\r
8460 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8461 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8462 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8463 if (forceVisible || exlen == 0 ||
\r
8464 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8465 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8466 /* Scroll to make new end of text visible if old end of text
\r
8467 was visible or new text is an echo of user typein */
\r
8468 sel.cpMin = 9999999;
\r
8469 sel.cpMax = 9999999;
\r
8470 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8471 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8472 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8473 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8475 if (savesel.cpMax == exlen || forceVisible) {
\r
8476 /* Move insert point to new end of text if it was at the old
\r
8477 end of text or if the new text is an echo of user typein */
\r
8478 sel.cpMin = 9999999;
\r
8479 sel.cpMax = 9999999;
\r
8480 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8482 /* Restore previous selection */
\r
8483 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8485 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8492 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8496 COLORREF oldFg, oldBg;
\r
8500 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8502 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8503 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8504 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8507 rect.right = x + squareSize;
\r
8509 rect.bottom = y + squareSize;
\r
8512 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8513 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8514 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8515 &rect, str, strlen(str), NULL);
\r
8517 (void) SetTextColor(hdc, oldFg);
\r
8518 (void) SetBkColor(hdc, oldBg);
\r
8519 (void) SelectObject(hdc, oldFont);
\r
8523 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8524 RECT *rect, char *color, char *flagFell)
\r
8528 COLORREF oldFg, oldBg;
\r
8531 if (appData.clockMode) {
\r
8533 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8535 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8542 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8543 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8545 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8546 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8548 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8552 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8553 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8554 rect, str, strlen(str), NULL);
\r
8555 if(logoHeight > 0 && appData.clockMode) {
\r
8557 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8558 r.top = rect->top + logoHeight/2;
\r
8559 r.left = rect->left;
\r
8560 r.right = rect->right;
\r
8561 r.bottom = rect->bottom;
\r
8562 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8563 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8564 &r, str, strlen(str), NULL);
\r
8566 (void) SetTextColor(hdc, oldFg);
\r
8567 (void) SetBkColor(hdc, oldBg);
\r
8568 (void) SelectObject(hdc, oldFont);
\r
8573 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8579 if( count <= 0 ) {
\r
8580 if (appData.debugMode) {
\r
8581 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8584 return ERROR_INVALID_USER_BUFFER;
\r
8587 ResetEvent(ovl->hEvent);
\r
8588 ovl->Offset = ovl->OffsetHigh = 0;
\r
8589 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8593 err = GetLastError();
\r
8594 if (err == ERROR_IO_PENDING) {
\r
8595 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8599 err = GetLastError();
\r
8606 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8611 ResetEvent(ovl->hEvent);
\r
8612 ovl->Offset = ovl->OffsetHigh = 0;
\r
8613 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8617 err = GetLastError();
\r
8618 if (err == ERROR_IO_PENDING) {
\r
8619 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8623 err = GetLastError();
\r
8629 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8630 void CheckForInputBufferFull( InputSource * is )
\r
8632 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8633 /* Look for end of line */
\r
8634 char * p = is->buf;
\r
8636 while( p < is->next && *p != '\n' ) {
\r
8640 if( p >= is->next ) {
\r
8641 if (appData.debugMode) {
\r
8642 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8645 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8646 is->count = (DWORD) -1;
\r
8647 is->next = is->buf;
\r
8653 InputThread(LPVOID arg)
\r
8658 is = (InputSource *) arg;
\r
8659 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8660 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8661 while (is->hThread != NULL) {
\r
8662 is->error = DoReadFile(is->hFile, is->next,
\r
8663 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8664 &is->count, &ovl);
\r
8665 if (is->error == NO_ERROR) {
\r
8666 is->next += is->count;
\r
8668 if (is->error == ERROR_BROKEN_PIPE) {
\r
8669 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8672 is->count = (DWORD) -1;
\r
8673 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8678 CheckForInputBufferFull( is );
\r
8680 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8682 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8684 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8687 CloseHandle(ovl.hEvent);
\r
8688 CloseHandle(is->hFile);
\r
8690 if (appData.debugMode) {
\r
8691 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8698 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8700 NonOvlInputThread(LPVOID arg)
\r
8707 is = (InputSource *) arg;
\r
8708 while (is->hThread != NULL) {
\r
8709 is->error = ReadFile(is->hFile, is->next,
\r
8710 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8711 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8712 if (is->error == NO_ERROR) {
\r
8713 /* Change CRLF to LF */
\r
8714 if (is->next > is->buf) {
\r
8716 i = is->count + 1;
\r
8724 if (prev == '\r' && *p == '\n') {
\r
8736 if (is->error == ERROR_BROKEN_PIPE) {
\r
8737 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8740 is->count = (DWORD) -1;
\r
8744 CheckForInputBufferFull( is );
\r
8746 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8748 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8750 if (is->count < 0) break; /* Quit on error */
\r
8752 CloseHandle(is->hFile);
\r
8757 SocketInputThread(LPVOID arg)
\r
8761 is = (InputSource *) arg;
\r
8762 while (is->hThread != NULL) {
\r
8763 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8764 if ((int)is->count == SOCKET_ERROR) {
\r
8765 is->count = (DWORD) -1;
\r
8766 is->error = WSAGetLastError();
\r
8768 is->error = NO_ERROR;
\r
8769 is->next += is->count;
\r
8770 if (is->count == 0 && is->second == is) {
\r
8771 /* End of file on stderr; quit with no message */
\r
8775 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8777 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8779 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8785 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8789 is = (InputSource *) lParam;
\r
8790 if (is->lineByLine) {
\r
8791 /* Feed in lines one by one */
\r
8792 char *p = is->buf;
\r
8794 while (q < is->next) {
\r
8795 if (*q++ == '\n') {
\r
8796 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8801 /* Move any partial line to the start of the buffer */
\r
8803 while (p < is->next) {
\r
8808 if (is->error != NO_ERROR || is->count == 0) {
\r
8809 /* Notify backend of the error. Note: If there was a partial
\r
8810 line at the end, it is not flushed through. */
\r
8811 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8814 /* Feed in the whole chunk of input at once */
\r
8815 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8816 is->next = is->buf;
\r
8820 /*---------------------------------------------------------------------------*\
\r
8822 * Menu enables. Used when setting various modes.
\r
8824 \*---------------------------------------------------------------------------*/
\r
8832 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8834 while (enab->item > 0) {
\r
8835 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8840 Enables gnuEnables[] = {
\r
8841 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8854 Enables icsEnables[] = {
\r
8855 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8856 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8871 Enables zippyEnables[] = {
\r
8872 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8873 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8874 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8879 Enables ncpEnables[] = {
\r
8880 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8884 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8885 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8886 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8887 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8888 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8889 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8890 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8891 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8892 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8893 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8894 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8898 Enables trainingOnEnables[] = {
\r
8899 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8900 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8901 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8902 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8903 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8904 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8905 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8906 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8910 Enables trainingOffEnables[] = {
\r
8911 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8912 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8913 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8914 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8915 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8916 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8917 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8918 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8922 /* These modify either ncpEnables or gnuEnables */
\r
8923 Enables cmailEnables[] = {
\r
8924 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8925 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8926 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8927 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8928 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8929 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8930 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8934 Enables machineThinkingEnables[] = {
\r
8935 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8936 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8937 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8938 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8939 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8940 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8941 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8942 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8943 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8944 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8945 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8946 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8947 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8948 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8949 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8953 Enables userThinkingEnables[] = {
\r
8954 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8955 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8956 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8957 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8958 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8959 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8960 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8961 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8962 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8963 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8964 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8965 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8966 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8967 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8968 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8972 /*---------------------------------------------------------------------------*\
\r
8974 * Front-end interface functions exported by XBoard.
\r
8975 * Functions appear in same order as prototypes in frontend.h.
\r
8977 \*---------------------------------------------------------------------------*/
\r
8981 static UINT prevChecked = 0;
\r
8982 static int prevPausing = 0;
\r
8985 if (pausing != prevPausing) {
\r
8986 prevPausing = pausing;
\r
8987 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8988 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8989 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8992 switch (gameMode) {
\r
8993 case BeginningOfGame:
\r
8994 if (appData.icsActive)
\r
8995 nowChecked = IDM_IcsClient;
\r
8996 else if (appData.noChessProgram)
\r
8997 nowChecked = IDM_EditGame;
\r
8999 nowChecked = IDM_MachineBlack;
\r
9001 case MachinePlaysBlack:
\r
9002 nowChecked = IDM_MachineBlack;
\r
9004 case MachinePlaysWhite:
\r
9005 nowChecked = IDM_MachineWhite;
\r
9007 case TwoMachinesPlay:
\r
9008 nowChecked = IDM_TwoMachines;
\r
9011 nowChecked = IDM_AnalysisMode;
\r
9014 nowChecked = IDM_AnalyzeFile;
\r
9017 nowChecked = IDM_EditGame;
\r
9019 case PlayFromGameFile:
\r
9020 nowChecked = IDM_LoadGame;
\r
9022 case EditPosition:
\r
9023 nowChecked = IDM_EditPosition;
\r
9026 nowChecked = IDM_Training;
\r
9028 case IcsPlayingWhite:
\r
9029 case IcsPlayingBlack:
\r
9030 case IcsObserving:
\r
9032 nowChecked = IDM_IcsClient;
\r
9039 if (prevChecked != 0)
\r
9040 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9041 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9042 if (nowChecked != 0)
\r
9043 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9044 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9046 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9047 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9048 MF_BYCOMMAND|MF_ENABLED);
\r
9050 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9051 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9054 prevChecked = nowChecked;
\r
9056 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9057 if (appData.icsActive) {
\r
9058 if (appData.icsEngineAnalyze) {
\r
9059 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9060 MF_BYCOMMAND|MF_CHECKED);
\r
9062 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9063 MF_BYCOMMAND|MF_UNCHECKED);
\r
9071 HMENU hmenu = GetMenu(hwndMain);
\r
9072 SetMenuEnables(hmenu, icsEnables);
\r
9073 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9074 MF_BYPOSITION|MF_ENABLED);
\r
9076 if (appData.zippyPlay) {
\r
9077 SetMenuEnables(hmenu, zippyEnables);
\r
9078 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9079 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9080 MF_BYCOMMAND|MF_ENABLED);
\r
9088 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9094 HMENU hmenu = GetMenu(hwndMain);
\r
9095 SetMenuEnables(hmenu, ncpEnables);
\r
9096 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9097 MF_BYPOSITION|MF_GRAYED);
\r
9098 DrawMenuBar(hwndMain);
\r
9104 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9108 SetTrainingModeOn()
\r
9111 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9112 for (i = 0; i < N_BUTTONS; i++) {
\r
9113 if (buttonDesc[i].hwnd != NULL)
\r
9114 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9119 VOID SetTrainingModeOff()
\r
9122 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9123 for (i = 0; i < N_BUTTONS; i++) {
\r
9124 if (buttonDesc[i].hwnd != NULL)
\r
9125 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9131 SetUserThinkingEnables()
\r
9133 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9137 SetMachineThinkingEnables()
\r
9139 HMENU hMenu = GetMenu(hwndMain);
\r
9140 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9142 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9144 if (gameMode == MachinePlaysBlack) {
\r
9145 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9146 } else if (gameMode == MachinePlaysWhite) {
\r
9147 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9148 } else if (gameMode == TwoMachinesPlay) {
\r
9149 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9155 DisplayTitle(char *str)
\r
9157 char title[MSG_SIZ], *host;
\r
9158 if (str[0] != NULLCHAR) {
\r
9159 strcpy(title, str);
\r
9160 } else if (appData.icsActive) {
\r
9161 if (appData.icsCommPort[0] != NULLCHAR)
\r
9164 host = appData.icsHost;
\r
9165 sprintf(title, "%s: %s", szTitle, host);
\r
9166 } else if (appData.noChessProgram) {
\r
9167 strcpy(title, szTitle);
\r
9169 strcpy(title, szTitle);
\r
9170 strcat(title, ": ");
\r
9171 strcat(title, first.tidy);
\r
9173 SetWindowText(hwndMain, title);
\r
9178 DisplayMessage(char *str1, char *str2)
\r
9182 int remain = MESSAGE_TEXT_MAX - 1;
\r
9185 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9186 messageText[0] = NULLCHAR;
\r
9188 len = strlen(str1);
\r
9189 if (len > remain) len = remain;
\r
9190 strncpy(messageText, str1, len);
\r
9191 messageText[len] = NULLCHAR;
\r
9194 if (*str2 && remain >= 2) {
\r
9196 strcat(messageText, " ");
\r
9199 len = strlen(str2);
\r
9200 if (len > remain) len = remain;
\r
9201 strncat(messageText, str2, len);
\r
9203 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9205 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9209 hdc = GetDC(hwndMain);
\r
9210 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9211 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9212 &messageRect, messageText, strlen(messageText), NULL);
\r
9213 (void) SelectObject(hdc, oldFont);
\r
9214 (void) ReleaseDC(hwndMain, hdc);
\r
9218 DisplayError(char *str, int error)
\r
9220 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9226 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9227 NULL, error, LANG_NEUTRAL,
\r
9228 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9230 sprintf(buf, "%s:\n%s", str, buf2);
\r
9232 ErrorMap *em = errmap;
\r
9233 while (em->err != 0 && em->err != error) em++;
\r
9234 if (em->err != 0) {
\r
9235 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9237 sprintf(buf, "%s:\nError code %d", str, error);
\r
9242 ErrorPopUp("Error", buf);
\r
9247 DisplayMoveError(char *str)
\r
9249 fromX = fromY = -1;
\r
9250 ClearHighlights();
\r
9251 DrawPosition(FALSE, NULL);
\r
9252 if (appData.popupMoveErrors) {
\r
9253 ErrorPopUp("Error", str);
\r
9255 DisplayMessage(str, "");
\r
9256 moveErrorMessageUp = TRUE;
\r
9261 DisplayFatalError(char *str, int error, int exitStatus)
\r
9263 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9265 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9268 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9269 NULL, error, LANG_NEUTRAL,
\r
9270 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9272 sprintf(buf, "%s:\n%s", str, buf2);
\r
9274 ErrorMap *em = errmap;
\r
9275 while (em->err != 0 && em->err != error) em++;
\r
9276 if (em->err != 0) {
\r
9277 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9279 sprintf(buf, "%s:\nError code %d", str, error);
\r
9284 if (appData.debugMode) {
\r
9285 fprintf(debugFP, "%s: %s\n", label, str);
\r
9287 if (appData.popupExitMessage) {
\r
9288 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9289 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9291 ExitEvent(exitStatus);
\r
9296 DisplayInformation(char *str)
\r
9298 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9303 DisplayNote(char *str)
\r
9305 ErrorPopUp("Note", str);
\r
9310 char *title, *question, *replyPrefix;
\r
9315 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9317 static QuestionParams *qp;
\r
9318 char reply[MSG_SIZ];
\r
9321 switch (message) {
\r
9322 case WM_INITDIALOG:
\r
9323 qp = (QuestionParams *) lParam;
\r
9324 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9325 SetWindowText(hDlg, qp->title);
\r
9326 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9327 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9331 switch (LOWORD(wParam)) {
\r
9333 strcpy(reply, qp->replyPrefix);
\r
9334 if (*reply) strcat(reply, " ");
\r
9335 len = strlen(reply);
\r
9336 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9337 strcat(reply, "\n");
\r
9338 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9339 EndDialog(hDlg, TRUE);
\r
9340 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9343 EndDialog(hDlg, FALSE);
\r
9354 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9356 QuestionParams qp;
\r
9360 qp.question = question;
\r
9361 qp.replyPrefix = replyPrefix;
\r
9363 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9364 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9365 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9366 FreeProcInstance(lpProc);
\r
9369 /* [AS] Pick FRC position */
\r
9370 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9372 static int * lpIndexFRC;
\r
9378 case WM_INITDIALOG:
\r
9379 lpIndexFRC = (int *) lParam;
\r
9381 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9383 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9384 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9385 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9386 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9391 switch( LOWORD(wParam) ) {
\r
9393 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9394 EndDialog( hDlg, 0 );
\r
9395 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9398 EndDialog( hDlg, 1 );
\r
9400 case IDC_NFG_Edit:
\r
9401 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9402 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9404 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9407 case IDC_NFG_Random:
\r
9408 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9409 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9422 int index = appData.defaultFrcPosition;
\r
9423 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9425 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9427 if( result == 0 ) {
\r
9428 appData.defaultFrcPosition = index;
\r
9434 /* [AS] Game list options */
\r
9440 static GLT_Item GLT_ItemInfo[] = {
\r
9441 { GLT_EVENT, "Event" },
\r
9442 { GLT_SITE, "Site" },
\r
9443 { GLT_DATE, "Date" },
\r
9444 { GLT_ROUND, "Round" },
\r
9445 { GLT_PLAYERS, "Players" },
\r
9446 { GLT_RESULT, "Result" },
\r
9447 { GLT_WHITE_ELO, "White Rating" },
\r
9448 { GLT_BLACK_ELO, "Black Rating" },
\r
9449 { GLT_TIME_CONTROL,"Time Control" },
\r
9450 { GLT_VARIANT, "Variant" },
\r
9451 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9452 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9456 const char * GLT_FindItem( char id )
\r
9458 const char * result = 0;
\r
9460 GLT_Item * list = GLT_ItemInfo;
\r
9462 while( list->id != 0 ) {
\r
9463 if( list->id == id ) {
\r
9464 result = list->name;
\r
9474 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9476 const char * name = GLT_FindItem( id );
\r
9479 if( index >= 0 ) {
\r
9480 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9483 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9488 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9492 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9495 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9499 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9501 pc = GLT_ALL_TAGS;
\r
9504 if( strchr( tags, *pc ) == 0 ) {
\r
9505 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9510 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9513 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9515 char result = '\0';
\r
9518 GLT_Item * list = GLT_ItemInfo;
\r
9520 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9521 while( list->id != 0 ) {
\r
9522 if( strcmp( list->name, name ) == 0 ) {
\r
9523 result = list->id;
\r
9534 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9536 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9537 int idx2 = idx1 + delta;
\r
9538 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9540 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9543 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9544 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9545 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9546 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9550 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9552 static char glt[64];
\r
9553 static char * lpUserGLT;
\r
9557 case WM_INITDIALOG:
\r
9558 lpUserGLT = (char *) lParam;
\r
9560 strcpy( glt, lpUserGLT );
\r
9562 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9564 /* Initialize list */
\r
9565 GLT_TagsToList( hDlg, glt );
\r
9567 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9572 switch( LOWORD(wParam) ) {
\r
9575 char * pc = lpUserGLT;
\r
9577 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9581 id = GLT_ListItemToTag( hDlg, idx );
\r
9585 } while( id != '\0' );
\r
9587 EndDialog( hDlg, 0 );
\r
9590 EndDialog( hDlg, 1 );
\r
9593 case IDC_GLT_Default:
\r
9594 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9595 GLT_TagsToList( hDlg, glt );
\r
9598 case IDC_GLT_Restore:
\r
9599 strcpy( glt, lpUserGLT );
\r
9600 GLT_TagsToList( hDlg, glt );
\r
9604 GLT_MoveSelection( hDlg, -1 );
\r
9607 case IDC_GLT_Down:
\r
9608 GLT_MoveSelection( hDlg, +1 );
\r
9618 int GameListOptions()
\r
9622 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9624 strcpy( glt, appData.gameListTags );
\r
9626 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9628 if( result == 0 ) {
\r
9629 /* [AS] Memory leak here! */
\r
9630 appData.gameListTags = strdup( glt );
\r
9638 DisplayIcsInteractionTitle(char *str)
\r
9640 char consoleTitle[MSG_SIZ];
\r
9642 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9643 SetWindowText(hwndConsole, consoleTitle);
\r
9647 DrawPosition(int fullRedraw, Board board)
\r
9649 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9656 fromX = fromY = -1;
\r
9657 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9658 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9659 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9660 dragInfo.lastpos = dragInfo.pos;
\r
9661 dragInfo.start.x = dragInfo.start.y = -1;
\r
9662 dragInfo.from = dragInfo.start;
\r
9664 DrawPosition(TRUE, NULL);
\r
9670 CommentPopUp(char *title, char *str)
\r
9672 HWND hwnd = GetActiveWindow();
\r
9673 EitherCommentPopUp(0, title, str, FALSE);
\r
9675 SetActiveWindow(hwnd);
\r
9679 CommentPopDown(void)
\r
9681 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9682 if (commentDialog) {
\r
9683 ShowWindow(commentDialog, SW_HIDE);
\r
9685 commentDialogUp = FALSE;
\r
9689 EditCommentPopUp(int index, char *title, char *str)
\r
9691 EitherCommentPopUp(index, title, str, TRUE);
\r
9698 MyPlaySound(&sounds[(int)SoundMove]);
\r
9701 VOID PlayIcsWinSound()
\r
9703 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9706 VOID PlayIcsLossSound()
\r
9708 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9711 VOID PlayIcsDrawSound()
\r
9713 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9716 VOID PlayIcsUnfinishedSound()
\r
9718 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9724 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9732 consoleEcho = TRUE;
\r
9733 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9734 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9735 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9744 consoleEcho = FALSE;
\r
9745 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9746 /* This works OK: set text and background both to the same color */
\r
9748 cf.crTextColor = COLOR_ECHOOFF;
\r
9749 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9750 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9753 /* No Raw()...? */
\r
9755 void Colorize(ColorClass cc, int continuation)
\r
9757 currentColorClass = cc;
\r
9758 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9759 consoleCF.crTextColor = textAttribs[cc].color;
\r
9760 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9761 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9767 static char buf[MSG_SIZ];
\r
9768 DWORD bufsiz = MSG_SIZ;
\r
9770 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9771 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9773 if (!GetUserName(buf, &bufsiz)) {
\r
9774 /*DisplayError("Error getting user name", GetLastError());*/
\r
9775 strcpy(buf, "User");
\r
9783 static char buf[MSG_SIZ];
\r
9784 DWORD bufsiz = MSG_SIZ;
\r
9786 if (!GetComputerName(buf, &bufsiz)) {
\r
9787 /*DisplayError("Error getting host name", GetLastError());*/
\r
9788 strcpy(buf, "Unknown");
\r
9795 ClockTimerRunning()
\r
9797 return clockTimerEvent != 0;
\r
9803 if (clockTimerEvent == 0) return FALSE;
\r
9804 KillTimer(hwndMain, clockTimerEvent);
\r
9805 clockTimerEvent = 0;
\r
9810 StartClockTimer(long millisec)
\r
9812 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9813 (UINT) millisec, NULL);
\r
9817 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9820 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9822 if(appData.noGUI) return;
\r
9823 hdc = GetDC(hwndMain);
\r
9824 if (!IsIconic(hwndMain)) {
\r
9825 DisplayAClock(hdc, timeRemaining, highlight,
\r
9826 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9828 if (highlight && iconCurrent == iconBlack) {
\r
9829 iconCurrent = iconWhite;
\r
9830 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9831 if (IsIconic(hwndMain)) {
\r
9832 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9835 (void) ReleaseDC(hwndMain, hdc);
\r
9837 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9841 DisplayBlackClock(long timeRemaining, int highlight)
\r
9844 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9846 if(appData.noGUI) return;
\r
9847 hdc = GetDC(hwndMain);
\r
9848 if (!IsIconic(hwndMain)) {
\r
9849 DisplayAClock(hdc, timeRemaining, highlight,
\r
9850 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9852 if (highlight && iconCurrent == iconWhite) {
\r
9853 iconCurrent = iconBlack;
\r
9854 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9855 if (IsIconic(hwndMain)) {
\r
9856 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9859 (void) ReleaseDC(hwndMain, hdc);
\r
9861 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9866 LoadGameTimerRunning()
\r
9868 return loadGameTimerEvent != 0;
\r
9872 StopLoadGameTimer()
\r
9874 if (loadGameTimerEvent == 0) return FALSE;
\r
9875 KillTimer(hwndMain, loadGameTimerEvent);
\r
9876 loadGameTimerEvent = 0;
\r
9881 StartLoadGameTimer(long millisec)
\r
9883 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9884 (UINT) millisec, NULL);
\r
9892 char fileTitle[MSG_SIZ];
\r
9894 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9895 f = OpenFileDialog(hwndMain, "a", defName,
\r
9896 appData.oldSaveStyle ? "gam" : "pgn",
\r
9898 "Save Game to File", NULL, fileTitle, NULL);
\r
9900 SaveGame(f, 0, "");
\r
9907 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9909 if (delayedTimerEvent != 0) {
\r
9910 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9911 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9913 KillTimer(hwndMain, delayedTimerEvent);
\r
9914 delayedTimerEvent = 0;
\r
9915 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9916 delayedTimerCallback();
\r
9918 delayedTimerCallback = cb;
\r
9919 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9920 (UINT) millisec, NULL);
\r
9923 DelayedEventCallback
\r
9926 if (delayedTimerEvent) {
\r
9927 return delayedTimerCallback;
\r
9934 CancelDelayedEvent()
\r
9936 if (delayedTimerEvent) {
\r
9937 KillTimer(hwndMain, delayedTimerEvent);
\r
9938 delayedTimerEvent = 0;
\r
9942 DWORD GetWin32Priority(int nice)
\r
9943 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9945 REALTIME_PRIORITY_CLASS 0x00000100
\r
9946 HIGH_PRIORITY_CLASS 0x00000080
\r
9947 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9948 NORMAL_PRIORITY_CLASS 0x00000020
\r
9949 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9950 IDLE_PRIORITY_CLASS 0x00000040
\r
9952 if (nice < -15) return 0x00000080;
\r
9953 if (nice < 0) return 0x00008000;
\r
9954 if (nice == 0) return 0x00000020;
\r
9955 if (nice < 15) return 0x00004000;
\r
9956 return 0x00000040;
\r
9959 /* Start a child process running the given program.
\r
9960 The process's standard output can be read from "from", and its
\r
9961 standard input can be written to "to".
\r
9962 Exit with fatal error if anything goes wrong.
\r
9963 Returns an opaque pointer that can be used to destroy the process
\r
9967 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9969 #define BUFSIZE 4096
\r
9971 HANDLE hChildStdinRd, hChildStdinWr,
\r
9972 hChildStdoutRd, hChildStdoutWr;
\r
9973 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9974 SECURITY_ATTRIBUTES saAttr;
\r
9976 PROCESS_INFORMATION piProcInfo;
\r
9977 STARTUPINFO siStartInfo;
\r
9979 char buf[MSG_SIZ];
\r
9982 if (appData.debugMode) {
\r
9983 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9988 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9989 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9990 saAttr.bInheritHandle = TRUE;
\r
9991 saAttr.lpSecurityDescriptor = NULL;
\r
9994 * The steps for redirecting child's STDOUT:
\r
9995 * 1. Create anonymous pipe to be STDOUT for child.
\r
9996 * 2. Create a noninheritable duplicate of read handle,
\r
9997 * and close the inheritable read handle.
\r
10000 /* Create a pipe for the child's STDOUT. */
\r
10001 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
10002 return GetLastError();
\r
10005 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
10006 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
10007 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
10008 FALSE, /* not inherited */
\r
10009 DUPLICATE_SAME_ACCESS);
\r
10010 if (! fSuccess) {
\r
10011 return GetLastError();
\r
10013 CloseHandle(hChildStdoutRd);
\r
10016 * The steps for redirecting child's STDIN:
\r
10017 * 1. Create anonymous pipe to be STDIN for child.
\r
10018 * 2. Create a noninheritable duplicate of write handle,
\r
10019 * and close the inheritable write handle.
\r
10022 /* Create a pipe for the child's STDIN. */
\r
10023 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
10024 return GetLastError();
\r
10027 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
10028 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
10029 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
10030 FALSE, /* not inherited */
\r
10031 DUPLICATE_SAME_ACCESS);
\r
10032 if (! fSuccess) {
\r
10033 return GetLastError();
\r
10035 CloseHandle(hChildStdinWr);
\r
10037 /* Arrange to (1) look in dir for the child .exe file, and
\r
10038 * (2) have dir be the child's working directory. Interpret
\r
10039 * dir relative to the directory WinBoard loaded from. */
\r
10040 GetCurrentDirectory(MSG_SIZ, buf);
\r
10041 SetCurrentDirectory(installDir);
\r
10042 SetCurrentDirectory(dir);
\r
10044 /* Now create the child process. */
\r
10046 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10047 siStartInfo.lpReserved = NULL;
\r
10048 siStartInfo.lpDesktop = NULL;
\r
10049 siStartInfo.lpTitle = NULL;
\r
10050 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10051 siStartInfo.cbReserved2 = 0;
\r
10052 siStartInfo.lpReserved2 = NULL;
\r
10053 siStartInfo.hStdInput = hChildStdinRd;
\r
10054 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10055 siStartInfo.hStdError = hChildStdoutWr;
\r
10057 fSuccess = CreateProcess(NULL,
\r
10058 cmdLine, /* command line */
\r
10059 NULL, /* process security attributes */
\r
10060 NULL, /* primary thread security attrs */
\r
10061 TRUE, /* handles are inherited */
\r
10062 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10063 NULL, /* use parent's environment */
\r
10065 &siStartInfo, /* STARTUPINFO pointer */
\r
10066 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10068 err = GetLastError();
\r
10069 SetCurrentDirectory(buf); /* return to prev directory */
\r
10070 if (! fSuccess) {
\r
10074 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10075 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10076 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10079 /* Close the handles we don't need in the parent */
\r
10080 CloseHandle(piProcInfo.hThread);
\r
10081 CloseHandle(hChildStdinRd);
\r
10082 CloseHandle(hChildStdoutWr);
\r
10084 /* Prepare return value */
\r
10085 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10086 cp->kind = CPReal;
\r
10087 cp->hProcess = piProcInfo.hProcess;
\r
10088 cp->pid = piProcInfo.dwProcessId;
\r
10089 cp->hFrom = hChildStdoutRdDup;
\r
10090 cp->hTo = hChildStdinWrDup;
\r
10092 *pr = (void *) cp;
\r
10094 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10095 2000 where engines sometimes don't see the initial command(s)
\r
10096 from WinBoard and hang. I don't understand how that can happen,
\r
10097 but the Sleep is harmless, so I've put it in. Others have also
\r
10098 reported what may be the same problem, so hopefully this will fix
\r
10099 it for them too. */
\r
10107 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10109 ChildProc *cp; int result;
\r
10111 cp = (ChildProc *) pr;
\r
10112 if (cp == NULL) return;
\r
10114 switch (cp->kind) {
\r
10116 /* TerminateProcess is considered harmful, so... */
\r
10117 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10118 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10119 /* The following doesn't work because the chess program
\r
10120 doesn't "have the same console" as WinBoard. Maybe
\r
10121 we could arrange for this even though neither WinBoard
\r
10122 nor the chess program uses a console for stdio? */
\r
10123 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10125 /* [AS] Special termination modes for misbehaving programs... */
\r
10126 if( signal == 9 ) {
\r
10127 result = TerminateProcess( cp->hProcess, 0 );
\r
10129 if ( appData.debugMode) {
\r
10130 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10133 else if( signal == 10 ) {
\r
10134 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10136 if( dw != WAIT_OBJECT_0 ) {
\r
10137 result = TerminateProcess( cp->hProcess, 0 );
\r
10139 if ( appData.debugMode) {
\r
10140 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10146 CloseHandle(cp->hProcess);
\r
10150 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10154 closesocket(cp->sock);
\r
10159 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10160 closesocket(cp->sock);
\r
10161 closesocket(cp->sock2);
\r
10169 InterruptChildProcess(ProcRef pr)
\r
10173 cp = (ChildProc *) pr;
\r
10174 if (cp == NULL) return;
\r
10175 switch (cp->kind) {
\r
10177 /* The following doesn't work because the chess program
\r
10178 doesn't "have the same console" as WinBoard. Maybe
\r
10179 we could arrange for this even though neither WinBoard
\r
10180 nor the chess program uses a console for stdio */
\r
10181 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10186 /* Can't interrupt */
\r
10190 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10197 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10199 char cmdLine[MSG_SIZ];
\r
10201 if (port[0] == NULLCHAR) {
\r
10202 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10204 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10206 return StartChildProcess(cmdLine, "", pr);
\r
10210 /* Code to open TCP sockets */
\r
10213 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10218 struct sockaddr_in sa, mysa;
\r
10219 struct hostent FAR *hp;
\r
10220 unsigned short uport;
\r
10221 WORD wVersionRequested;
\r
10224 /* Initialize socket DLL */
\r
10225 wVersionRequested = MAKEWORD(1, 1);
\r
10226 err = WSAStartup(wVersionRequested, &wsaData);
\r
10227 if (err != 0) return err;
\r
10229 /* Make socket */
\r
10230 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10231 err = WSAGetLastError();
\r
10236 /* Bind local address using (mostly) don't-care values.
\r
10238 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10239 mysa.sin_family = AF_INET;
\r
10240 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10241 uport = (unsigned short) 0;
\r
10242 mysa.sin_port = htons(uport);
\r
10243 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10244 == SOCKET_ERROR) {
\r
10245 err = WSAGetLastError();
\r
10250 /* Resolve remote host name */
\r
10251 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10252 if (!(hp = gethostbyname(host))) {
\r
10253 unsigned int b0, b1, b2, b3;
\r
10255 err = WSAGetLastError();
\r
10257 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10258 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10259 hp->h_addrtype = AF_INET;
\r
10260 hp->h_length = 4;
\r
10261 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10262 hp->h_addr_list[0] = (char *) malloc(4);
\r
10263 hp->h_addr_list[0][0] = (char) b0;
\r
10264 hp->h_addr_list[0][1] = (char) b1;
\r
10265 hp->h_addr_list[0][2] = (char) b2;
\r
10266 hp->h_addr_list[0][3] = (char) b3;
\r
10272 sa.sin_family = hp->h_addrtype;
\r
10273 uport = (unsigned short) atoi(port);
\r
10274 sa.sin_port = htons(uport);
\r
10275 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10277 /* Make connection */
\r
10278 if (connect(s, (struct sockaddr *) &sa,
\r
10279 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10280 err = WSAGetLastError();
\r
10285 /* Prepare return value */
\r
10286 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10287 cp->kind = CPSock;
\r
10289 *pr = (ProcRef *) cp;
\r
10295 OpenCommPort(char *name, ProcRef *pr)
\r
10300 char fullname[MSG_SIZ];
\r
10302 if (*name != '\\')
\r
10303 sprintf(fullname, "\\\\.\\%s", name);
\r
10305 strcpy(fullname, name);
\r
10307 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10308 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10309 if (h == (HANDLE) -1) {
\r
10310 return GetLastError();
\r
10314 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10316 /* Accumulate characters until a 100ms pause, then parse */
\r
10317 ct.ReadIntervalTimeout = 100;
\r
10318 ct.ReadTotalTimeoutMultiplier = 0;
\r
10319 ct.ReadTotalTimeoutConstant = 0;
\r
10320 ct.WriteTotalTimeoutMultiplier = 0;
\r
10321 ct.WriteTotalTimeoutConstant = 0;
\r
10322 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10324 /* Prepare return value */
\r
10325 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10326 cp->kind = CPComm;
\r
10329 *pr = (ProcRef *) cp;
\r
10335 OpenLoopback(ProcRef *pr)
\r
10337 DisplayFatalError("Not implemented", 0, 1);
\r
10343 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10347 SOCKET s, s2, s3;
\r
10348 struct sockaddr_in sa, mysa;
\r
10349 struct hostent FAR *hp;
\r
10350 unsigned short uport;
\r
10351 WORD wVersionRequested;
\r
10354 char stderrPortStr[MSG_SIZ];
\r
10356 /* Initialize socket DLL */
\r
10357 wVersionRequested = MAKEWORD(1, 1);
\r
10358 err = WSAStartup(wVersionRequested, &wsaData);
\r
10359 if (err != 0) return err;
\r
10361 /* Resolve remote host name */
\r
10362 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10363 if (!(hp = gethostbyname(host))) {
\r
10364 unsigned int b0, b1, b2, b3;
\r
10366 err = WSAGetLastError();
\r
10368 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10369 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10370 hp->h_addrtype = AF_INET;
\r
10371 hp->h_length = 4;
\r
10372 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10373 hp->h_addr_list[0] = (char *) malloc(4);
\r
10374 hp->h_addr_list[0][0] = (char) b0;
\r
10375 hp->h_addr_list[0][1] = (char) b1;
\r
10376 hp->h_addr_list[0][2] = (char) b2;
\r
10377 hp->h_addr_list[0][3] = (char) b3;
\r
10383 sa.sin_family = hp->h_addrtype;
\r
10384 uport = (unsigned short) 514;
\r
10385 sa.sin_port = htons(uport);
\r
10386 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10388 /* Bind local socket to unused "privileged" port address
\r
10390 s = INVALID_SOCKET;
\r
10391 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10392 mysa.sin_family = AF_INET;
\r
10393 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10394 for (fromPort = 1023;; fromPort--) {
\r
10395 if (fromPort < 0) {
\r
10397 return WSAEADDRINUSE;
\r
10399 if (s == INVALID_SOCKET) {
\r
10400 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10401 err = WSAGetLastError();
\r
10406 uport = (unsigned short) fromPort;
\r
10407 mysa.sin_port = htons(uport);
\r
10408 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10409 == SOCKET_ERROR) {
\r
10410 err = WSAGetLastError();
\r
10411 if (err == WSAEADDRINUSE) continue;
\r
10415 if (connect(s, (struct sockaddr *) &sa,
\r
10416 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10417 err = WSAGetLastError();
\r
10418 if (err == WSAEADDRINUSE) {
\r
10429 /* Bind stderr local socket to unused "privileged" port address
\r
10431 s2 = INVALID_SOCKET;
\r
10432 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10433 mysa.sin_family = AF_INET;
\r
10434 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10435 for (fromPort = 1023;; fromPort--) {
\r
10436 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10437 if (fromPort < 0) {
\r
10438 (void) closesocket(s);
\r
10440 return WSAEADDRINUSE;
\r
10442 if (s2 == INVALID_SOCKET) {
\r
10443 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10444 err = WSAGetLastError();
\r
10450 uport = (unsigned short) fromPort;
\r
10451 mysa.sin_port = htons(uport);
\r
10452 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10453 == SOCKET_ERROR) {
\r
10454 err = WSAGetLastError();
\r
10455 if (err == WSAEADDRINUSE) continue;
\r
10456 (void) closesocket(s);
\r
10460 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10461 err = WSAGetLastError();
\r
10462 if (err == WSAEADDRINUSE) {
\r
10464 s2 = INVALID_SOCKET;
\r
10467 (void) closesocket(s);
\r
10468 (void) closesocket(s2);
\r
10474 prevStderrPort = fromPort; // remember port used
\r
10475 sprintf(stderrPortStr, "%d", fromPort);
\r
10477 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10478 err = WSAGetLastError();
\r
10479 (void) closesocket(s);
\r
10480 (void) closesocket(s2);
\r
10485 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10486 err = WSAGetLastError();
\r
10487 (void) closesocket(s);
\r
10488 (void) closesocket(s2);
\r
10492 if (*user == NULLCHAR) user = UserName();
\r
10493 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10494 err = WSAGetLastError();
\r
10495 (void) closesocket(s);
\r
10496 (void) closesocket(s2);
\r
10500 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10501 err = WSAGetLastError();
\r
10502 (void) closesocket(s);
\r
10503 (void) closesocket(s2);
\r
10508 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10509 err = WSAGetLastError();
\r
10510 (void) closesocket(s);
\r
10511 (void) closesocket(s2);
\r
10515 (void) closesocket(s2); /* Stop listening */
\r
10517 /* Prepare return value */
\r
10518 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10519 cp->kind = CPRcmd;
\r
10522 *pr = (ProcRef *) cp;
\r
10529 AddInputSource(ProcRef pr, int lineByLine,
\r
10530 InputCallback func, VOIDSTAR closure)
\r
10532 InputSource *is, *is2 = NULL;
\r
10533 ChildProc *cp = (ChildProc *) pr;
\r
10535 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10536 is->lineByLine = lineByLine;
\r
10538 is->closure = closure;
\r
10539 is->second = NULL;
\r
10540 is->next = is->buf;
\r
10541 if (pr == NoProc) {
\r
10542 is->kind = CPReal;
\r
10543 consoleInputSource = is;
\r
10545 is->kind = cp->kind;
\r
10547 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10548 we create all threads suspended so that the is->hThread variable can be
\r
10549 safely assigned, then let the threads start with ResumeThread.
\r
10551 switch (cp->kind) {
\r
10553 is->hFile = cp->hFrom;
\r
10554 cp->hFrom = NULL; /* now owned by InputThread */
\r
10556 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10557 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10561 is->hFile = cp->hFrom;
\r
10562 cp->hFrom = NULL; /* now owned by InputThread */
\r
10564 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10565 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10569 is->sock = cp->sock;
\r
10571 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10572 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10576 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10578 is->sock = cp->sock;
\r
10579 is->second = is2;
\r
10580 is2->sock = cp->sock2;
\r
10581 is2->second = is2;
\r
10583 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10584 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10586 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10587 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10591 if( is->hThread != NULL ) {
\r
10592 ResumeThread( is->hThread );
\r
10595 if( is2 != NULL && is2->hThread != NULL ) {
\r
10596 ResumeThread( is2->hThread );
\r
10600 return (InputSourceRef) is;
\r
10604 RemoveInputSource(InputSourceRef isr)
\r
10608 is = (InputSource *) isr;
\r
10609 is->hThread = NULL; /* tell thread to stop */
\r
10610 CloseHandle(is->hThread);
\r
10611 if (is->second != NULL) {
\r
10612 is->second->hThread = NULL;
\r
10613 CloseHandle(is->second->hThread);
\r
10619 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10622 int outCount = SOCKET_ERROR;
\r
10623 ChildProc *cp = (ChildProc *) pr;
\r
10624 static OVERLAPPED ovl;
\r
10626 if (pr == NoProc) {
\r
10627 ConsoleOutput(message, count, FALSE);
\r
10631 if (ovl.hEvent == NULL) {
\r
10632 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10634 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10636 switch (cp->kind) {
\r
10639 outCount = send(cp->sock, message, count, 0);
\r
10640 if (outCount == SOCKET_ERROR) {
\r
10641 *outError = WSAGetLastError();
\r
10643 *outError = NO_ERROR;
\r
10648 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10649 &dOutCount, NULL)) {
\r
10650 *outError = NO_ERROR;
\r
10651 outCount = (int) dOutCount;
\r
10653 *outError = GetLastError();
\r
10658 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10659 &dOutCount, &ovl);
\r
10660 if (*outError == NO_ERROR) {
\r
10661 outCount = (int) dOutCount;
\r
10669 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10672 /* Ignore delay, not implemented for WinBoard */
\r
10673 return OutputToProcess(pr, message, count, outError);
\r
10678 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10679 char *buf, int count, int error)
\r
10681 DisplayFatalError("Not implemented", 0, 1);
\r
10684 /* see wgamelist.c for Game List functions */
\r
10685 /* see wedittags.c for Edit Tags functions */
\r
10692 char buf[MSG_SIZ];
\r
10695 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10696 f = fopen(buf, "r");
\r
10698 ProcessICSInitScript(f);
\r
10706 StartAnalysisClock()
\r
10708 if (analysisTimerEvent) return;
\r
10709 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10710 (UINT) 2000, NULL);
\r
10714 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10716 static HANDLE hwndText;
\r
10718 static int sizeX, sizeY;
\r
10719 int newSizeX, newSizeY, flags;
\r
10722 switch (message) {
\r
10723 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10724 /* Initialize the dialog items */
\r
10725 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10726 SetWindowText(hDlg, analysisTitle);
\r
10727 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10728 /* Size and position the dialog */
\r
10729 if (!analysisDialog) {
\r
10730 analysisDialog = hDlg;
\r
10731 flags = SWP_NOZORDER;
\r
10732 GetClientRect(hDlg, &rect);
\r
10733 sizeX = rect.right;
\r
10734 sizeY = rect.bottom;
\r
10735 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10736 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10737 WINDOWPLACEMENT wp;
\r
10738 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10739 wp.length = sizeof(WINDOWPLACEMENT);
\r
10741 wp.showCmd = SW_SHOW;
\r
10742 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10743 wp.rcNormalPosition.left = analysisX;
\r
10744 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10745 wp.rcNormalPosition.top = analysisY;
\r
10746 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10747 SetWindowPlacement(hDlg, &wp);
\r
10749 GetClientRect(hDlg, &rect);
\r
10750 newSizeX = rect.right;
\r
10751 newSizeY = rect.bottom;
\r
10752 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10753 newSizeX, newSizeY);
\r
10754 sizeX = newSizeX;
\r
10755 sizeY = newSizeY;
\r
10760 case WM_COMMAND: /* message: received a command */
\r
10761 switch (LOWORD(wParam)) {
\r
10763 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10764 ExitAnalyzeMode();
\r
10776 newSizeX = LOWORD(lParam);
\r
10777 newSizeY = HIWORD(lParam);
\r
10778 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10779 sizeX = newSizeX;
\r
10780 sizeY = newSizeY;
\r
10783 case WM_GETMINMAXINFO:
\r
10784 /* Prevent resizing window too small */
\r
10785 mmi = (MINMAXINFO *) lParam;
\r
10786 mmi->ptMinTrackSize.x = 100;
\r
10787 mmi->ptMinTrackSize.y = 100;
\r
10794 AnalysisPopUp(char* title, char* str)
\r
10800 EngineOutputPopUp();
\r
10803 if (str == NULL) str = "";
\r
10804 p = (char *) malloc(2 * strlen(str) + 2);
\r
10807 if (*str == '\n') *q++ = '\r';
\r
10811 if (analysisText != NULL) free(analysisText);
\r
10812 analysisText = p;
\r
10814 if (analysisDialog) {
\r
10815 SetWindowText(analysisDialog, title);
\r
10816 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10817 ShowWindow(analysisDialog, SW_SHOW);
\r
10819 analysisTitle = title;
\r
10820 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10821 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10822 hwndMain, (DLGPROC)lpProc);
\r
10823 FreeProcInstance(lpProc);
\r
10825 analysisDialogUp = TRUE;
\r
10829 AnalysisPopDown()
\r
10831 if (analysisDialog) {
\r
10832 ShowWindow(analysisDialog, SW_HIDE);
\r
10834 analysisDialogUp = FALSE;
\r
10839 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10841 highlightInfo.sq[0].x = fromX;
\r
10842 highlightInfo.sq[0].y = fromY;
\r
10843 highlightInfo.sq[1].x = toX;
\r
10844 highlightInfo.sq[1].y = toY;
\r
10848 ClearHighlights()
\r
10850 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10851 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10855 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10857 premoveHighlightInfo.sq[0].x = fromX;
\r
10858 premoveHighlightInfo.sq[0].y = fromY;
\r
10859 premoveHighlightInfo.sq[1].x = toX;
\r
10860 premoveHighlightInfo.sq[1].y = toY;
\r
10864 ClearPremoveHighlights()
\r
10866 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10867 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10871 ShutDownFrontEnd()
\r
10873 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10874 DeleteClipboardTempFiles();
\r
10880 if (IsIconic(hwndMain))
\r
10881 ShowWindow(hwndMain, SW_RESTORE);
\r
10883 SetActiveWindow(hwndMain);
\r
10887 * Prototypes for animation support routines
\r
10889 static void ScreenSquare(int column, int row, POINT * pt);
\r
10890 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10891 POINT frames[], int * nFrames);
\r
10895 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10896 { // [HGM] atomic: animate blast wave
\r
10898 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10899 explodeInfo.fromX = fromX;
\r
10900 explodeInfo.fromY = fromY;
\r
10901 explodeInfo.toX = toX;
\r
10902 explodeInfo.toY = toY;
\r
10903 for(i=1; i<nFrames; i++) {
\r
10904 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10905 DrawPosition(FALSE, NULL);
\r
10906 Sleep(appData.animSpeed);
\r
10908 explodeInfo.radius = 0;
\r
10909 DrawPosition(TRUE, NULL);
\r
10912 #define kFactor 4
\r
10915 AnimateMove(board, fromX, fromY, toX, toY)
\r
10922 ChessSquare piece;
\r
10923 POINT start, finish, mid;
\r
10924 POINT frames[kFactor * 2 + 1];
\r
10927 if (!appData.animate) return;
\r
10928 if (doingSizing) return;
\r
10929 if (fromY < 0 || fromX < 0) return;
\r
10930 piece = board[fromY][fromX];
\r
10931 if (piece >= EmptySquare) return;
\r
10933 ScreenSquare(fromX, fromY, &start);
\r
10934 ScreenSquare(toX, toY, &finish);
\r
10936 /* All pieces except knights move in straight line */
\r
10937 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10938 mid.x = start.x + (finish.x - start.x) / 2;
\r
10939 mid.y = start.y + (finish.y - start.y) / 2;
\r
10941 /* Knight: make diagonal movement then straight */
\r
10942 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10943 mid.x = start.x + (finish.x - start.x) / 2;
\r
10944 mid.y = finish.y;
\r
10946 mid.x = finish.x;
\r
10947 mid.y = start.y + (finish.y - start.y) / 2;
\r
10951 /* Don't use as many frames for very short moves */
\r
10952 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10953 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10955 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10957 animInfo.from.x = fromX;
\r
10958 animInfo.from.y = fromY;
\r
10959 animInfo.to.x = toX;
\r
10960 animInfo.to.y = toY;
\r
10961 animInfo.lastpos = start;
\r
10962 animInfo.piece = piece;
\r
10963 for (n = 0; n < nFrames; n++) {
\r
10964 animInfo.pos = frames[n];
\r
10965 DrawPosition(FALSE, NULL);
\r
10966 animInfo.lastpos = animInfo.pos;
\r
10967 Sleep(appData.animSpeed);
\r
10969 animInfo.pos = finish;
\r
10970 DrawPosition(FALSE, NULL);
\r
10971 animInfo.piece = EmptySquare;
\r
10972 if(gameInfo.variant == VariantAtomic &&
\r
10973 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10974 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10977 /* Convert board position to corner of screen rect and color */
\r
10980 ScreenSquare(column, row, pt)
\r
10981 int column; int row; POINT * pt;
\r
10984 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10985 pt->y = lineGap + row * (squareSize + lineGap);
\r
10987 pt->x = lineGap + column * (squareSize + lineGap);
\r
10988 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10992 /* Generate a series of frame coords from start->mid->finish.
\r
10993 The movement rate doubles until the half way point is
\r
10994 reached, then halves back down to the final destination,
\r
10995 which gives a nice slow in/out effect. The algorithmn
\r
10996 may seem to generate too many intermediates for short
\r
10997 moves, but remember that the purpose is to attract the
\r
10998 viewers attention to the piece about to be moved and
\r
10999 then to where it ends up. Too few frames would be less
\r
11003 Tween(start, mid, finish, factor, frames, nFrames)
\r
11004 POINT * start; POINT * mid;
\r
11005 POINT * finish; int factor;
\r
11006 POINT frames[]; int * nFrames;
\r
11008 int n, fraction = 1, count = 0;
\r
11010 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
11011 for (n = 0; n < factor; n++)
\r
11013 for (n = 0; n < factor; n++) {
\r
11014 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
11015 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
11017 fraction = fraction / 2;
\r
11021 frames[count] = *mid;
\r
11024 /* Slow out, stepping 1/2, then 1/4, ... */
\r
11026 for (n = 0; n < factor; n++) {
\r
11027 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
11028 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
11030 fraction = fraction * 2;
\r
11032 *nFrames = count;
\r
11036 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11041 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11042 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11044 OutputDebugString( buf );
\r
11047 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11049 EvalGraphSet( first, last, current, pvInfoList );
\r
11052 void SetProgramStats( FrontEndProgramStats * stats )
\r
11057 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11058 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11060 OutputDebugString( buf );
\r
11063 EngineOutputUpdate( stats );
\r