2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
96 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 POINT pos; /* window coordinates of current pos */
\r
101 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
102 POINT from; /* board coordinates of the piece's orig pos */
\r
103 POINT to; /* board coordinates of the piece's new pos */
\r
106 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
109 POINT start; /* window coordinates of start pos */
\r
110 POINT pos; /* window coordinates of current pos */
\r
111 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
112 POINT from; /* board coordinates of the piece's orig pos */
\r
115 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
118 POINT sq[2]; /* board coordinates of from, to squares */
\r
121 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
122 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
124 /* Window class names */
\r
125 char szAppName[] = "WinBoard";
\r
126 char szConsoleName[] = "WBConsole";
\r
128 /* Title bar text */
\r
129 char szTitle[] = "WinBoard";
\r
130 char szConsoleTitle[] = "ICS Interaction";
\r
133 char *settingsFileName;
\r
134 BOOLEAN saveSettingsOnExit;
\r
135 char installDir[MSG_SIZ];
\r
137 BoardSize boardSize;
\r
138 BOOLEAN chessProgram;
\r
139 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
140 static int squareSize, lineGap;
\r
141 static int winWidth, winHeight;
\r
142 static RECT messageRect, whiteRect, blackRect;
\r
143 static char messageText[MESSAGE_TEXT_MAX];
\r
144 static int clockTimerEvent = 0;
\r
145 static int loadGameTimerEvent = 0;
\r
146 static int analysisTimerEvent = 0;
\r
147 static DelayedEventCallback delayedTimerCallback;
\r
148 static int delayedTimerEvent = 0;
\r
149 static int buttonCount = 2;
\r
150 char *icsTextMenuString;
\r
152 char *firstChessProgramNames;
\r
153 char *secondChessProgramNames;
\r
155 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
157 #define PALETTESIZE 256
\r
159 HINSTANCE hInst; /* current instance */
\r
160 HWND hwndMain = NULL; /* root window*/
\r
161 HWND hwndConsole = NULL;
\r
162 BOOLEAN alwaysOnTop = FALSE;
\r
164 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
165 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
167 ColorClass currentColorClass;
\r
169 HWND hCommPort = NULL; /* currently open comm port */
\r
170 static HWND hwndPause; /* pause button */
\r
171 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
172 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
173 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
174 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
175 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
176 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
177 static HPEN gridPen = NULL;
\r
178 static HPEN highlightPen = NULL;
\r
179 static HPEN premovePen = NULL;
\r
180 static NPLOGPALETTE pLogPal;
\r
181 static BOOL paletteChanged = FALSE;
\r
182 static HICON iconWhite, iconBlack, iconCurrent;
\r
183 static int doingSizing = FALSE;
\r
184 static int lastSizing = 0;
\r
185 static int prevStderrPort;
\r
187 /* [AS] Support for background textures */
\r
188 #define BACK_TEXTURE_MODE_DISABLED 0
\r
189 #define BACK_TEXTURE_MODE_PLAIN 1
\r
190 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
192 static HBITMAP liteBackTexture = NULL;
\r
193 static HBITMAP darkBackTexture = NULL;
\r
194 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
195 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int backTextureSquareSize = 0;
\r
197 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
199 #if __GNUC__ && !defined(_winmajor)
\r
200 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
202 #define oldDialog (_winmajor < 4)
\r
205 char *defaultTextAttribs[] =
\r
207 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
208 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
218 int cliWidth, cliHeight;
\r
221 SizeInfo sizeInfo[] =
\r
223 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
224 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
225 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
226 { "petite", 33, 1, 1, 1, 0, 0 },
\r
227 { "slim", 37, 2, 1, 0, 0, 0 },
\r
228 { "small", 40, 2, 1, 0, 0, 0 },
\r
229 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
230 { "middling", 49, 2, 0, 0, 0, 0 },
\r
231 { "average", 54, 2, 0, 0, 0, 0 },
\r
232 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
233 { "medium", 64, 3, 0, 0, 0, 0 },
\r
234 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
235 { "large", 80, 3, 0, 0, 0, 0 },
\r
236 { "big", 87, 3, 0, 0, 0, 0 },
\r
237 { "huge", 95, 3, 0, 0, 0, 0 },
\r
238 { "giant", 108, 3, 0, 0, 0, 0 },
\r
239 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
240 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
241 { NULL, 0, 0, 0, 0, 0, 0 }
\r
244 #define MF(x) {x, {0, }, {0, }, 0}
\r
245 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
247 { 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
248 { 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
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
267 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
276 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
277 #define N_BUTTONS 5
\r
279 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
281 {"<<", IDM_ToStart, NULL, NULL},
\r
282 {"<", IDM_Backward, NULL, NULL},
\r
283 {"P", IDM_Pause, NULL, NULL},
\r
284 {">", IDM_Forward, NULL, NULL},
\r
285 {">>", IDM_ToEnd, NULL, NULL},
\r
288 int tinyLayout = 0, smallLayout = 0;
\r
289 #define MENU_BAR_ITEMS 6
\r
290 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
291 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
292 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
296 MySound sounds[(int)NSoundClasses];
\r
297 MyTextAttribs textAttribs[(int)NColorClasses];
\r
299 MyColorizeAttribs colorizeAttribs[] = {
\r
300 { (COLORREF)0, 0, "Shout Text" },
\r
301 { (COLORREF)0, 0, "SShout/CShout" },
\r
302 { (COLORREF)0, 0, "Channel 1 Text" },
\r
303 { (COLORREF)0, 0, "Channel Text" },
\r
304 { (COLORREF)0, 0, "Kibitz Text" },
\r
305 { (COLORREF)0, 0, "Tell Text" },
\r
306 { (COLORREF)0, 0, "Challenge Text" },
\r
307 { (COLORREF)0, 0, "Request Text" },
\r
308 { (COLORREF)0, 0, "Seek Text" },
\r
309 { (COLORREF)0, 0, "Normal Text" },
\r
310 { (COLORREF)0, 0, "None" }
\r
315 static char *commentTitle;
\r
316 static char *commentText;
\r
317 static int commentIndex;
\r
318 static Boolean editComment = FALSE;
\r
319 HWND commentDialog = NULL;
\r
320 BOOLEAN commentDialogUp = FALSE;
\r
321 static int commentX, commentY, commentH, commentW;
\r
323 static char *analysisTitle;
\r
324 static char *analysisText;
\r
325 HWND analysisDialog = NULL;
\r
326 BOOLEAN analysisDialogUp = FALSE;
\r
327 static int analysisX, analysisY, analysisH, analysisW;
\r
329 char errorTitle[MSG_SIZ];
\r
330 char errorMessage[2*MSG_SIZ];
\r
331 HWND errorDialog = NULL;
\r
332 BOOLEAN moveErrorMessageUp = FALSE;
\r
333 BOOLEAN consoleEcho = TRUE;
\r
334 CHARFORMAT consoleCF;
\r
335 COLORREF consoleBackgroundColor;
\r
337 char *programVersion;
\r
343 typedef int CPKind;
\r
352 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
355 #define INPUT_SOURCE_BUF_SIZE 4096
\r
357 typedef struct _InputSource {
\r
364 char buf[INPUT_SOURCE_BUF_SIZE];
\r
368 InputCallback func;
\r
369 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
373 InputSource *consoleInputSource;
\r
378 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
379 VOID ConsoleCreate();
\r
381 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
382 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
383 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
384 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
386 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
387 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
388 void ParseIcsTextMenu(char *icsTextMenuString);
\r
389 VOID PopUpMoveDialog(char firstchar);
\r
390 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
394 int GameListOptions();
\r
396 HWND moveHistoryDialog = NULL;
\r
397 BOOLEAN moveHistoryDialogUp = FALSE;
\r
399 WindowPlacement wpMoveHistory;
\r
401 HWND evalGraphDialog = NULL;
\r
402 BOOLEAN evalGraphDialogUp = FALSE;
\r
404 WindowPlacement wpEvalGraph;
\r
406 HWND engineOutputDialog = NULL;
\r
407 BOOLEAN engineOutputDialogUp = FALSE;
\r
409 WindowPlacement wpEngineOutput;
\r
411 VOID MoveHistoryPopUp();
\r
412 VOID MoveHistoryPopDown();
\r
413 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
414 BOOL MoveHistoryIsUp();
\r
416 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
417 VOID EvalGraphPopUp();
\r
418 VOID EvalGraphPopDown();
\r
419 BOOL EvalGraphIsUp();
\r
421 VOID EngineOutputPopUp();
\r
422 VOID EngineOutputPopDown();
\r
423 BOOL EngineOutputIsUp();
\r
424 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
426 VOID GothicPopUp(char *title);
\r
428 * Setting "frozen" should disable all user input other than deleting
\r
429 * the window. We do this while engines are initializing themselves.
\r
431 static int frozen = 0;
\r
432 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
438 if (frozen) return;
\r
440 hmenu = GetMenu(hwndMain);
\r
441 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
442 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
444 DrawMenuBar(hwndMain);
\r
447 /* Undo a FreezeUI */
\r
453 if (!frozen) return;
\r
455 hmenu = GetMenu(hwndMain);
\r
456 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
457 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
459 DrawMenuBar(hwndMain);
\r
462 /*---------------------------------------------------------------------------*\
\r
466 \*---------------------------------------------------------------------------*/
\r
469 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
470 LPSTR lpCmdLine, int nCmdShow)
\r
473 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
477 LoadLibrary("RICHED32.DLL");
\r
478 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
480 if (!InitApplication(hInstance)) {
\r
483 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
487 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
488 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
489 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
491 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
493 while (GetMessage(&msg, /* message structure */
\r
494 NULL, /* handle of window receiving the message */
\r
495 0, /* lowest message to examine */
\r
496 0)) /* highest message to examine */
\r
498 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
499 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
500 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
501 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
502 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
503 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
504 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
505 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
506 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
507 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
508 TranslateMessage(&msg); /* Translates virtual key codes */
\r
509 DispatchMessage(&msg); /* Dispatches message to window */
\r
514 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
517 /*---------------------------------------------------------------------------*\
\r
519 * Initialization functions
\r
521 \*---------------------------------------------------------------------------*/
\r
524 InitApplication(HINSTANCE hInstance)
\r
528 /* Fill in window class structure with parameters that describe the */
\r
531 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
532 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
533 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
534 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
535 wc.hInstance = hInstance; /* Owner of this class */
\r
536 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
537 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
538 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
539 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
540 wc.lpszClassName = szAppName; /* Name to register as */
\r
542 /* Register the window class and return success/failure code. */
\r
543 if (!RegisterClass(&wc)) return FALSE;
\r
545 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
546 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
548 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
549 wc.hInstance = hInstance;
\r
550 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
551 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
552 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
553 wc.lpszMenuName = NULL;
\r
554 wc.lpszClassName = szConsoleName;
\r
556 if (!RegisterClass(&wc)) return FALSE;
\r
561 /* Set by InitInstance, used by EnsureOnScreen */
\r
562 int screenHeight, screenWidth;
\r
565 EnsureOnScreen(int *x, int *y)
\r
567 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
568 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
569 if (*x > screenWidth - 32) *x = 0;
\r
570 if (*y > screenHeight - 32) *y = 0;
\r
571 if (*x < 10) *x = 10;
\r
572 if (*y < gap) *y = gap;
\r
576 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
578 HWND hwnd; /* Main window handle. */
\r
580 WINDOWPLACEMENT wp;
\r
583 hInst = hInstance; /* Store instance handle in our global variable */
\r
585 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
586 *filepart = NULLCHAR;
\r
588 GetCurrentDirectory(MSG_SIZ, installDir);
\r
590 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
591 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
592 if (appData.debugMode) {
\r
593 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
594 setbuf(debugFP, NULL);
\r
599 InitEngineUCI( installDir, &first );
\r
600 InitEngineUCI( installDir, &second );
\r
602 /* Create a main window for this application instance. */
\r
603 hwnd = CreateWindow(szAppName, szTitle,
\r
604 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
605 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
606 NULL, NULL, hInstance, NULL);
\r
609 /* If window could not be created, return "failure" */
\r
614 iconWhite = LoadIcon(hInstance, "icon_white");
\r
615 iconBlack = LoadIcon(hInstance, "icon_black");
\r
616 iconCurrent = iconWhite;
\r
617 InitDrawingColors();
\r
618 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
619 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
620 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
621 /* Compute window size for each board size, and use the largest
\r
622 size that fits on this screen as the default. */
\r
623 InitDrawingSizes((BoardSize)ibs, 0);
\r
624 if (boardSize == (BoardSize)-1 &&
\r
625 winHeight <= screenHeight
\r
626 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
627 && winWidth <= screenWidth) {
\r
628 boardSize = (BoardSize)ibs;
\r
631 InitDrawingSizes(boardSize, 0);
\r
633 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
635 /* [AS] Load textures if specified */
\r
636 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
638 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
639 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
640 liteBackTextureMode = appData.liteBackTextureMode;
\r
642 if (liteBackTexture == NULL && appData.debugMode) {
\r
643 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
647 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
648 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
649 darkBackTextureMode = appData.darkBackTextureMode;
\r
651 if (darkBackTexture == NULL && appData.debugMode) {
\r
652 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
656 mysrandom( (unsigned) time(NULL) );
\r
658 /* Make a console window if needed */
\r
659 if (appData.icsActive) {
\r
663 /* [AS] Restore layout */
\r
664 if( wpMoveHistory.visible ) {
\r
665 MoveHistoryPopUp();
\r
668 if( wpEvalGraph.visible ) {
\r
672 if( wpEngineOutput.visible ) {
\r
673 EngineOutputPopUp();
\r
678 /* Make the window visible; update its client area; and return "success" */
\r
679 EnsureOnScreen(&boardX, &boardY);
\r
680 wp.length = sizeof(WINDOWPLACEMENT);
\r
682 wp.showCmd = nCmdShow;
\r
683 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
684 wp.rcNormalPosition.left = boardX;
\r
685 wp.rcNormalPosition.right = boardX + winWidth;
\r
686 wp.rcNormalPosition.top = boardY;
\r
687 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
688 SetWindowPlacement(hwndMain, &wp);
\r
690 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
691 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
693 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
694 if( gameInfo.variant != VariantFischeRandom ) {
\r
695 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
699 /* [HGM] Gothic licensing requirement */
\r
700 if(gameInfo.variant == VariantGothic)
\r
701 GothicPopUp(GOTHIC);
\r
706 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
707 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
709 ShowWindow(hwndConsole, nCmdShow);
\r
711 UpdateWindow(hwnd);
\r
719 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
720 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
721 ArgSettingsFilename
\r
729 String *pString; // ArgString
\r
730 int *pInt; // ArgInt
\r
731 float *pFloat; // ArgFloat
\r
732 Boolean *pBoolean; // ArgBoolean
\r
733 COLORREF *pColor; // ArgColor
\r
734 ColorClass cc; // ArgAttribs
\r
735 String *pFilename; // ArgFilename
\r
736 BoardSize *pBoardSize; // ArgBoardSize
\r
737 int whichFont; // ArgFont
\r
738 DCB *pDCB; // ArgCommSettings
\r
739 String *pFilename; // ArgSettingsFilename
\r
747 ArgDescriptor argDescriptors[] = {
\r
748 /* positional arguments */
\r
749 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
750 { "", ArgNone, NULL },
\r
751 /* keyword arguments */
\r
752 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
753 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
754 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
755 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
756 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
757 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
758 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
759 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
760 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
761 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
762 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
763 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
764 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
765 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
766 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
767 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
768 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
769 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
771 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
773 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
775 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
776 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
778 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
779 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
780 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
781 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
782 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
783 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
784 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
785 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
786 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
787 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
788 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
789 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
790 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
791 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
792 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
793 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
794 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
795 /*!!bitmapDirectory?*/
\r
796 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
797 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
798 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
799 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
800 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
801 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
802 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
803 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
804 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
805 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
806 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
807 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
808 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
809 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
810 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
811 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
812 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
813 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
814 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
815 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
816 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
817 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
818 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
819 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
820 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
821 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
822 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
823 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
824 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
825 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
826 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
827 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
828 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
829 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
830 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
831 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
832 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
833 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
834 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
835 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
836 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
837 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
838 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
839 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
840 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
841 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
842 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
843 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
844 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
845 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
846 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
847 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
848 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
849 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
850 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
851 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
852 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
853 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
854 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
855 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
856 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
857 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
858 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
859 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
860 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
861 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
862 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
863 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
864 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
865 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
866 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
867 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
868 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
869 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
870 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
871 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
872 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
873 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
874 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
875 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
876 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
877 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
878 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
879 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
880 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
881 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
882 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
883 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
884 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
885 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
886 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
887 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
888 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
889 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
890 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
891 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
892 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
893 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
894 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
895 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
896 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
897 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
898 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
899 TRUE }, /* must come after all fonts */
\r
900 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
901 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
902 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
903 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
904 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
905 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
906 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
907 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
908 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
909 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
910 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
911 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
912 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
913 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
914 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
915 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
916 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
917 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
918 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
919 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
920 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
921 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
922 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
923 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
924 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
925 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
926 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
927 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
928 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
929 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
930 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
932 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
933 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
935 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
936 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
937 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
938 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
939 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
940 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
941 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
942 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
943 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
944 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
945 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
946 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
947 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
948 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
949 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
950 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
951 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
952 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
953 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
954 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
955 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
956 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
957 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
958 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
959 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
960 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
961 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
962 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
963 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
964 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
965 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
966 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
967 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
968 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
969 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
970 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
971 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
972 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
973 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
974 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
975 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
976 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
977 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
978 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
979 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
980 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
981 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
982 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
983 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
984 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
985 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
986 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
987 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
988 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
989 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
990 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
991 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
992 { "highlightLastMove", ArgBoolean,
\r
993 (LPVOID) &appData.highlightLastMove, TRUE },
\r
994 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
995 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
996 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
997 { "highlightDragging", ArgBoolean,
\r
998 (LPVOID) &appData.highlightDragging, TRUE },
\r
999 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1000 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1001 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1002 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1003 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1004 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1005 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1006 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1007 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1008 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1009 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1010 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1011 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1012 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1013 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1014 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1015 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1016 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1017 { "soundShout", ArgFilename,
\r
1018 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1019 { "soundSShout", ArgFilename,
\r
1020 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1021 { "soundChannel1", ArgFilename,
\r
1022 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1023 { "soundChannel", ArgFilename,
\r
1024 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1025 { "soundKibitz", ArgFilename,
\r
1026 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1027 { "soundTell", ArgFilename,
\r
1028 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1029 { "soundChallenge", ArgFilename,
\r
1030 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1031 { "soundRequest", ArgFilename,
\r
1032 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1033 { "soundSeek", ArgFilename,
\r
1034 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1035 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1036 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1037 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1038 { "soundIcsLoss", ArgFilename,
\r
1039 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1040 { "soundIcsDraw", ArgFilename,
\r
1041 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1042 { "soundIcsUnfinished", ArgFilename,
\r
1043 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1044 { "soundIcsAlarm", ArgFilename,
\r
1045 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1046 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1047 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1048 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1049 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1050 { "reuseChessPrograms", ArgBoolean,
\r
1051 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1052 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1053 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1054 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1055 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1056 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1057 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1058 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1059 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1060 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1061 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1062 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1063 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1064 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1065 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1066 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1067 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1068 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1069 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1070 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1071 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1072 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1073 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1074 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1075 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1076 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1077 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1078 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1079 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1080 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1081 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1082 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1083 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1084 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1085 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1086 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1087 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1088 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1090 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1092 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1093 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1094 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1095 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1096 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1097 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1098 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1099 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1100 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1101 /* [AS] New features */
\r
1102 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1103 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1104 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1105 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1106 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1107 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1108 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1109 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1110 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1111 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1112 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1113 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1114 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1115 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1116 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1117 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1118 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1119 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1120 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1121 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1122 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1123 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1124 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1125 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1126 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1127 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1128 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1129 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1130 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1131 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1132 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1133 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1134 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1135 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1136 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1137 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1138 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1139 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1140 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1141 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1142 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1143 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1144 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1145 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1146 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1147 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1148 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1149 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1151 /* [AS] Layout stuff */
\r
1152 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1153 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1154 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1155 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1156 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1158 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1159 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1160 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1161 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1162 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1164 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1165 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1166 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1167 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1168 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1170 /* [HGM] board-size, adjudication and misc. options */
\r
1171 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1172 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1173 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1174 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, FALSE },
\r
1175 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, TRUE },
\r
1176 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1177 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1178 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1179 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1180 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1181 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1184 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1185 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1186 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1187 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1188 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1189 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1190 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1191 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1192 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1193 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1194 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1195 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1196 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1198 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1199 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1200 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1201 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1202 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1203 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1204 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1206 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1207 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1208 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1209 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1210 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1211 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1212 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1213 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1214 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1215 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1216 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1217 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1218 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1219 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1220 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1221 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1222 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1223 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1225 { NULL, ArgNone, NULL, FALSE }
\r
1229 /* Kludge for indirection files on command line */
\r
1230 char* lastIndirectionFilename;
\r
1231 ArgDescriptor argDescriptorIndirection =
\r
1232 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1236 ExitArgError(char *msg, char *badArg)
\r
1238 char buf[MSG_SIZ];
\r
1240 sprintf(buf, "%s %s", msg, badArg);
\r
1241 DisplayFatalError(buf, 0, 2);
\r
1245 /* Command line font name parser. NULL name means do nothing.
\r
1246 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1247 For backward compatibility, syntax without the colon is also
\r
1248 accepted, but font names with digits in them won't work in that case.
\r
1251 ParseFontName(char *name, MyFontParams *mfp)
\r
1254 if (name == NULL) return;
\r
1256 q = strchr(p, ':');
\r
1258 if (q - p >= sizeof(mfp->faceName))
\r
1259 ExitArgError("Font name too long:", name);
\r
1260 memcpy(mfp->faceName, p, q - p);
\r
1261 mfp->faceName[q - p] = NULLCHAR;
\r
1264 q = mfp->faceName;
\r
1265 while (*p && !isdigit(*p)) {
\r
1267 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1268 ExitArgError("Font name too long:", name);
\r
1270 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1273 if (!*p) ExitArgError("Font point size missing:", name);
\r
1274 mfp->pointSize = (float) atof(p);
\r
1275 mfp->bold = (strchr(p, 'b') != NULL);
\r
1276 mfp->italic = (strchr(p, 'i') != NULL);
\r
1277 mfp->underline = (strchr(p, 'u') != NULL);
\r
1278 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1281 /* Color name parser.
\r
1282 X version accepts X color names, but this one
\r
1283 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1285 ParseColorName(char *name)
\r
1287 int red, green, blue, count;
\r
1288 char buf[MSG_SIZ];
\r
1290 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1292 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1293 &red, &green, &blue);
\r
1296 sprintf(buf, "Can't parse color name %s", name);
\r
1297 DisplayError(buf, 0);
\r
1298 return RGB(0, 0, 0);
\r
1300 return PALETTERGB(red, green, blue);
\r
1304 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1306 char *e = argValue;
\r
1310 if (*e == 'b') eff |= CFE_BOLD;
\r
1311 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1312 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1313 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1314 else if (*e == '#' || isdigit(*e)) break;
\r
1318 *color = ParseColorName(e);
\r
1323 ParseBoardSize(char *name)
\r
1325 BoardSize bs = SizeTiny;
\r
1326 while (sizeInfo[bs].name != NULL) {
\r
1327 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1330 ExitArgError("Unrecognized board size value", name);
\r
1331 return bs; /* not reached */
\r
1336 StringGet(void *getClosure)
\r
1338 char **p = (char **) getClosure;
\r
1343 FileGet(void *getClosure)
\r
1346 FILE* f = (FILE*) getClosure;
\r
1355 /* Parse settings file named "name". If file found, return the
\r
1356 full name in fullname and return TRUE; else return FALSE */
\r
1358 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1363 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1364 f = fopen(fullname, "r");
\r
1366 ParseArgs(FileGet, f);
\r
1375 ParseArgs(GetFunc get, void *cl)
\r
1377 char argName[ARG_MAX];
\r
1378 char argValue[ARG_MAX];
\r
1379 ArgDescriptor *ad;
\r
1388 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1389 if (ch == NULLCHAR) break;
\r
1391 /* Comment to end of line */
\r
1393 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1395 } else if (ch == '/' || ch == '-') {
\r
1398 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1399 ch != '\n' && ch != '\t') {
\r
1405 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1406 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1408 if (ad->argName == NULL)
\r
1409 ExitArgError("Unrecognized argument", argName);
\r
1411 } else if (ch == '@') {
\r
1412 /* Indirection file */
\r
1413 ad = &argDescriptorIndirection;
\r
1416 /* Positional argument */
\r
1417 ad = &argDescriptors[posarg++];
\r
1418 strcpy(argName, ad->argName);
\r
1421 if (ad->argType == ArgTrue) {
\r
1422 *(Boolean *) ad->argLoc = TRUE;
\r
1425 if (ad->argType == ArgFalse) {
\r
1426 *(Boolean *) ad->argLoc = FALSE;
\r
1430 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1431 if (ch == NULLCHAR || ch == '\n') {
\r
1432 ExitArgError("No value provided for argument", argName);
\r
1436 // Quoting with { }. No characters have to (or can) be escaped.
\r
1437 // Thus the string cannot contain a '}' character.
\r
1457 } else if (ch == '\'' || ch == '"') {
\r
1458 // Quoting with ' ' or " ", with \ as escape character.
\r
1459 // Inconvenient for long strings that may contain Windows filenames.
\r
1476 if (ch == start) {
\r
1485 if (ad->argType == ArgFilename
\r
1486 || ad->argType == ArgSettingsFilename) {
\r
1492 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1516 for (i = 0; i < 3; i++) {
\r
1517 if (ch >= '0' && ch <= '7') {
\r
1518 octval = octval*8 + (ch - '0');
\r
1525 *q++ = (char) octval;
\r
1536 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1543 switch (ad->argType) {
\r
1545 *(int *) ad->argLoc = atoi(argValue);
\r
1549 *(float *) ad->argLoc = (float) atof(argValue);
\r
1554 *(char **) ad->argLoc = strdup(argValue);
\r
1557 case ArgSettingsFilename:
\r
1559 char fullname[MSG_SIZ];
\r
1560 if (ParseSettingsFile(argValue, fullname)) {
\r
1561 if (ad->argLoc != NULL) {
\r
1562 *(char **) ad->argLoc = strdup(fullname);
\r
1565 if (ad->argLoc != NULL) {
\r
1567 ExitArgError("Failed to open indirection file", argValue);
\r
1574 switch (argValue[0]) {
\r
1577 *(Boolean *) ad->argLoc = TRUE;
\r
1581 *(Boolean *) ad->argLoc = FALSE;
\r
1584 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1590 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1593 case ArgAttribs: {
\r
1594 ColorClass cc = (ColorClass)ad->argLoc;
\r
1595 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1599 case ArgBoardSize:
\r
1600 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1604 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1607 case ArgCommSettings:
\r
1608 ParseCommSettings(argValue, &dcb);
\r
1612 ExitArgError("Unrecognized argument", argValue);
\r
1619 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1621 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1622 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1625 lf->lfEscapement = 0;
\r
1626 lf->lfOrientation = 0;
\r
1627 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1628 lf->lfItalic = mfp->italic;
\r
1629 lf->lfUnderline = mfp->underline;
\r
1630 lf->lfStrikeOut = mfp->strikeout;
\r
1631 lf->lfCharSet = DEFAULT_CHARSET;
\r
1632 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1633 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1634 lf->lfQuality = DEFAULT_QUALITY;
\r
1635 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1636 strcpy(lf->lfFaceName, mfp->faceName);
\r
1640 CreateFontInMF(MyFont *mf)
\r
1642 LFfromMFP(&mf->lf, &mf->mfp);
\r
1643 if (mf->hf) DeleteObject(mf->hf);
\r
1644 mf->hf = CreateFontIndirect(&mf->lf);
\r
1648 SetDefaultTextAttribs()
\r
1651 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1652 ParseAttribs(&textAttribs[cc].color,
\r
1653 &textAttribs[cc].effects,
\r
1654 defaultTextAttribs[cc]);
\r
1659 SetDefaultSounds()
\r
1663 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1664 textAttribs[cc].sound.name = strdup("");
\r
1665 textAttribs[cc].sound.data = NULL;
\r
1667 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1668 sounds[sc].name = strdup("");
\r
1669 sounds[sc].data = NULL;
\r
1671 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1679 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1680 MyLoadSound(&textAttribs[cc].sound);
\r
1682 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1683 MyLoadSound(&sounds[sc]);
\r
1688 InitAppData(LPSTR lpCmdLine)
\r
1691 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1694 programName = szAppName;
\r
1696 /* Initialize to defaults */
\r
1697 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1698 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1699 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1700 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1701 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1702 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1703 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1704 SetDefaultTextAttribs();
\r
1705 SetDefaultSounds();
\r
1706 appData.movesPerSession = MOVES_PER_SESSION;
\r
1707 appData.initString = INIT_STRING;
\r
1708 appData.secondInitString = INIT_STRING;
\r
1709 appData.firstComputerString = COMPUTER_STRING;
\r
1710 appData.secondComputerString = COMPUTER_STRING;
\r
1711 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1712 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1713 appData.firstPlaysBlack = FALSE;
\r
1714 appData.noChessProgram = FALSE;
\r
1715 chessProgram = FALSE;
\r
1716 appData.firstHost = FIRST_HOST;
\r
1717 appData.secondHost = SECOND_HOST;
\r
1718 appData.firstDirectory = FIRST_DIRECTORY;
\r
1719 appData.secondDirectory = SECOND_DIRECTORY;
\r
1720 appData.bitmapDirectory = "";
\r
1721 appData.remoteShell = REMOTE_SHELL;
\r
1722 appData.remoteUser = "";
\r
1723 appData.timeDelay = TIME_DELAY;
\r
1724 appData.timeControl = TIME_CONTROL;
\r
1725 appData.timeIncrement = TIME_INCREMENT;
\r
1726 appData.icsActive = FALSE;
\r
1727 appData.icsHost = "";
\r
1728 appData.icsPort = ICS_PORT;
\r
1729 appData.icsCommPort = ICS_COMM_PORT;
\r
1730 appData.icsLogon = ICS_LOGON;
\r
1731 appData.icsHelper = "";
\r
1732 appData.useTelnet = FALSE;
\r
1733 appData.telnetProgram = TELNET_PROGRAM;
\r
1734 appData.gateway = "";
\r
1735 appData.loadGameFile = "";
\r
1736 appData.loadGameIndex = 0;
\r
1737 appData.saveGameFile = "";
\r
1738 appData.autoSaveGames = FALSE;
\r
1739 appData.loadPositionFile = "";
\r
1740 appData.loadPositionIndex = 1;
\r
1741 appData.savePositionFile = "";
\r
1742 appData.matchMode = FALSE;
\r
1743 appData.matchGames = 0;
\r
1744 appData.monoMode = FALSE;
\r
1745 appData.debugMode = FALSE;
\r
1746 appData.clockMode = TRUE;
\r
1747 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1748 appData.Iconic = FALSE; /*unused*/
\r
1749 appData.searchTime = "";
\r
1750 appData.searchDepth = 0;
\r
1751 appData.showCoords = FALSE;
\r
1752 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1753 appData.autoCallFlag = FALSE;
\r
1754 appData.flipView = FALSE;
\r
1755 appData.autoFlipView = TRUE;
\r
1756 appData.cmailGameName = "";
\r
1757 appData.alwaysPromoteToQueen = FALSE;
\r
1758 appData.oldSaveStyle = FALSE;
\r
1759 appData.quietPlay = FALSE;
\r
1760 appData.showThinking = FALSE;
\r
1761 appData.ponderNextMove = TRUE;
\r
1762 appData.periodicUpdates = TRUE;
\r
1763 appData.popupExitMessage = TRUE;
\r
1764 appData.popupMoveErrors = FALSE;
\r
1765 appData.autoObserve = FALSE;
\r
1766 appData.autoComment = FALSE;
\r
1767 appData.animate = TRUE;
\r
1768 appData.animSpeed = 10;
\r
1769 appData.animateDragging = TRUE;
\r
1770 appData.highlightLastMove = TRUE;
\r
1771 appData.getMoveList = TRUE;
\r
1772 appData.testLegality = TRUE;
\r
1773 appData.premove = TRUE;
\r
1774 appData.premoveWhite = FALSE;
\r
1775 appData.premoveWhiteText = "";
\r
1776 appData.premoveBlack = FALSE;
\r
1777 appData.premoveBlackText = "";
\r
1778 appData.icsAlarm = TRUE;
\r
1779 appData.icsAlarmTime = 5000;
\r
1780 appData.autoRaiseBoard = TRUE;
\r
1781 appData.localLineEditing = TRUE;
\r
1782 appData.colorize = TRUE;
\r
1783 appData.reuseFirst = TRUE;
\r
1784 appData.reuseSecond = TRUE;
\r
1785 appData.blindfold = FALSE;
\r
1786 dcb.DCBlength = sizeof(DCB);
\r
1787 dcb.BaudRate = 9600;
\r
1788 dcb.fBinary = TRUE;
\r
1789 dcb.fParity = FALSE;
\r
1790 dcb.fOutxCtsFlow = FALSE;
\r
1791 dcb.fOutxDsrFlow = FALSE;
\r
1792 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1793 dcb.fDsrSensitivity = FALSE;
\r
1794 dcb.fTXContinueOnXoff = TRUE;
\r
1795 dcb.fOutX = FALSE;
\r
1797 dcb.fNull = FALSE;
\r
1798 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1799 dcb.fAbortOnError = FALSE;
\r
1800 dcb.wReserved = 0;
\r
1802 dcb.Parity = SPACEPARITY;
\r
1803 dcb.StopBits = ONESTOPBIT;
\r
1804 settingsFileName = SETTINGS_FILE;
\r
1805 saveSettingsOnExit = TRUE;
\r
1806 boardX = CW_USEDEFAULT;
\r
1807 boardY = CW_USEDEFAULT;
\r
1808 consoleX = CW_USEDEFAULT;
\r
1809 consoleY = CW_USEDEFAULT;
\r
1810 consoleW = CW_USEDEFAULT;
\r
1811 consoleH = CW_USEDEFAULT;
\r
1812 analysisX = CW_USEDEFAULT;
\r
1813 analysisY = CW_USEDEFAULT;
\r
1814 analysisW = CW_USEDEFAULT;
\r
1815 analysisH = CW_USEDEFAULT;
\r
1816 commentX = CW_USEDEFAULT;
\r
1817 commentY = CW_USEDEFAULT;
\r
1818 commentW = CW_USEDEFAULT;
\r
1819 commentH = CW_USEDEFAULT;
\r
1820 editTagsX = CW_USEDEFAULT;
\r
1821 editTagsY = CW_USEDEFAULT;
\r
1822 editTagsW = CW_USEDEFAULT;
\r
1823 editTagsH = CW_USEDEFAULT;
\r
1824 gameListX = CW_USEDEFAULT;
\r
1825 gameListY = CW_USEDEFAULT;
\r
1826 gameListW = CW_USEDEFAULT;
\r
1827 gameListH = CW_USEDEFAULT;
\r
1828 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1829 icsNames = ICS_NAMES;
\r
1830 firstChessProgramNames = FCP_NAMES;
\r
1831 secondChessProgramNames = SCP_NAMES;
\r
1832 appData.initialMode = "";
\r
1833 appData.variant = "normal";
\r
1834 appData.firstProtocolVersion = PROTOVER;
\r
1835 appData.secondProtocolVersion = PROTOVER;
\r
1836 appData.showButtonBar = TRUE;
\r
1838 /* [AS] New properties (see comments in header file) */
\r
1839 appData.firstScoreIsAbsolute = FALSE;
\r
1840 appData.secondScoreIsAbsolute = FALSE;
\r
1841 appData.saveExtendedInfoInPGN = FALSE;
\r
1842 appData.hideThinkingFromHuman = FALSE;
\r
1843 appData.liteBackTextureFile = "";
\r
1844 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1845 appData.darkBackTextureFile = "";
\r
1846 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1847 appData.renderPiecesWithFont = "";
\r
1848 appData.fontToPieceTable = "";
\r
1849 appData.fontBackColorWhite = 0;
\r
1850 appData.fontForeColorWhite = 0;
\r
1851 appData.fontBackColorBlack = 0;
\r
1852 appData.fontForeColorBlack = 0;
\r
1853 appData.fontPieceSize = 80;
\r
1854 appData.overrideLineGap = 1;
\r
1855 appData.adjudicateLossThreshold = 0;
\r
1856 appData.delayBeforeQuit = 0;
\r
1857 appData.delayAfterQuit = 0;
\r
1858 appData.nameOfDebugFile = "winboard.debug";
\r
1859 appData.pgnEventHeader = "Computer Chess Game";
\r
1860 appData.defaultFrcPosition = -1;
\r
1861 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1862 appData.saveOutOfBookInfo = TRUE;
\r
1863 appData.showEvalInMoveHistory = TRUE;
\r
1864 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1865 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1866 appData.highlightMoveWithArrow = FALSE;
\r
1867 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1868 appData.useStickyWindows = TRUE;
\r
1869 appData.adjudicateDrawMoves = 0;
\r
1870 appData.autoDisplayComment = TRUE;
\r
1871 appData.autoDisplayTags = TRUE;
\r
1872 appData.firstIsUCI = FALSE;
\r
1873 appData.secondIsUCI = FALSE;
\r
1874 appData.firstHasOwnBookUCI = TRUE;
\r
1875 appData.secondHasOwnBookUCI = TRUE;
\r
1876 appData.polyglotDir = "";
\r
1877 appData.usePolyglotBook = FALSE;
\r
1878 appData.polyglotBook = "";
\r
1879 appData.defaultHashSize = 64;
\r
1880 appData.defaultCacheSizeEGTB = 4;
\r
1881 appData.defaultPathEGTB = "c:\\egtb";
\r
1883 InitWindowPlacement( &wpMoveHistory );
\r
1884 InitWindowPlacement( &wpEvalGraph );
\r
1885 InitWindowPlacement( &wpEngineOutput );
\r
1887 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1888 appData.NrFiles = -1;
\r
1889 appData.NrRanks = -1;
\r
1890 appData.holdingsSize = -1;
\r
1891 appData.testClaims = FALSE;
\r
1892 appData.checkMates = FALSE;
\r
1893 appData.materialDraws= FALSE;
\r
1894 appData.trivialDraws = FALSE;
\r
1895 appData.ruleMoves = 51;
\r
1896 appData.drawRepeats = 6;
\r
1897 appData.matchPause = 10000;
\r
1898 appData.alphaRank = FALSE;
\r
1901 appData.zippyTalk = ZIPPY_TALK;
\r
1902 appData.zippyPlay = ZIPPY_PLAY;
\r
1903 appData.zippyLines = ZIPPY_LINES;
\r
1904 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1905 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1906 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1907 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1908 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1909 appData.zippyUseI = ZIPPY_USE_I;
\r
1910 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1911 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1912 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1913 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1914 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1915 appData.zippyAbort = ZIPPY_ABORT;
\r
1916 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1917 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1918 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1921 /* Point font array elements to structures and
\r
1922 parse default font names */
\r
1923 for (i=0; i<NUM_FONTS; i++) {
\r
1924 for (j=0; j<NUM_SIZES; j++) {
\r
1925 font[j][i] = &fontRec[j][i];
\r
1926 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1930 /* Parse default settings file if any */
\r
1931 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1932 settingsFileName = strdup(buf);
\r
1935 /* Parse command line */
\r
1936 ParseArgs(StringGet, &lpCmdLine);
\r
1938 /* [HGM] make sure board size is acceptable */
\r
1939 if(appData.NrFiles > BOARD_SIZE ||
\r
1940 appData.NrRanks > BOARD_SIZE )
\r
1941 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1943 /* Propagate options that affect others */
\r
1944 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1945 if (appData.icsActive || appData.noChessProgram) {
\r
1946 chessProgram = FALSE; /* not local chess program mode */
\r
1949 /* Open startup dialog if needed */
\r
1950 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1951 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1952 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1953 *appData.secondChessProgram == NULLCHAR))) {
\r
1956 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1957 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1958 FreeProcInstance(lpProc);
\r
1961 /* Make sure save files land in the right (?) directory */
\r
1962 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1963 appData.saveGameFile = strdup(buf);
\r
1965 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1966 appData.savePositionFile = strdup(buf);
\r
1969 /* Finish initialization for fonts and sounds */
\r
1970 for (i=0; i<NUM_FONTS; i++) {
\r
1971 for (j=0; j<NUM_SIZES; j++) {
\r
1972 CreateFontInMF(font[j][i]);
\r
1975 /* xboard, and older WinBoards, controlled the move sound with the
\r
1976 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1977 always turn the option on (so that the backend will call us),
\r
1978 then let the user turn the sound off by setting it to silence if
\r
1979 desired. To accommodate old winboard.ini files saved by old
\r
1980 versions of WinBoard, we also turn off the sound if the option
\r
1981 was initially set to false. */
\r
1982 if (!appData.ringBellAfterMoves) {
\r
1983 sounds[(int)SoundMove].name = strdup("");
\r
1984 appData.ringBellAfterMoves = TRUE;
\r
1986 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1987 SetCurrentDirectory(installDir);
\r
1989 SetCurrentDirectory(currDir);
\r
1991 p = icsTextMenuString;
\r
1992 if (p[0] == '@') {
\r
1993 FILE* f = fopen(p + 1, "r");
\r
1995 DisplayFatalError(p + 1, errno, 2);
\r
1998 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2000 buf[i] = NULLCHAR;
\r
2003 ParseIcsTextMenu(strdup(p));
\r
2010 HMENU hmenu = GetMenu(hwndMain);
\r
2012 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2013 MF_BYCOMMAND|((appData.icsActive &&
\r
2014 *appData.icsCommPort != NULLCHAR) ?
\r
2015 MF_ENABLED : MF_GRAYED));
\r
2016 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2017 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2018 MF_CHECKED : MF_UNCHECKED));
\r
2023 SaveSettings(char* name)
\r
2026 ArgDescriptor *ad;
\r
2027 WINDOWPLACEMENT wp;
\r
2028 char dir[MSG_SIZ];
\r
2030 if (!hwndMain) return;
\r
2032 GetCurrentDirectory(MSG_SIZ, dir);
\r
2033 SetCurrentDirectory(installDir);
\r
2034 f = fopen(name, "w");
\r
2035 SetCurrentDirectory(dir);
\r
2037 DisplayError(name, errno);
\r
2040 fprintf(f, ";\n");
\r
2041 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2042 fprintf(f, ";\n");
\r
2043 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2044 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2045 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2046 fprintf(f, ";\n");
\r
2048 wp.length = sizeof(WINDOWPLACEMENT);
\r
2049 GetWindowPlacement(hwndMain, &wp);
\r
2050 boardX = wp.rcNormalPosition.left;
\r
2051 boardY = wp.rcNormalPosition.top;
\r
2053 if (hwndConsole) {
\r
2054 GetWindowPlacement(hwndConsole, &wp);
\r
2055 consoleX = wp.rcNormalPosition.left;
\r
2056 consoleY = wp.rcNormalPosition.top;
\r
2057 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2058 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2061 if (analysisDialog) {
\r
2062 GetWindowPlacement(analysisDialog, &wp);
\r
2063 analysisX = wp.rcNormalPosition.left;
\r
2064 analysisY = wp.rcNormalPosition.top;
\r
2065 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2066 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2069 if (commentDialog) {
\r
2070 GetWindowPlacement(commentDialog, &wp);
\r
2071 commentX = wp.rcNormalPosition.left;
\r
2072 commentY = wp.rcNormalPosition.top;
\r
2073 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2074 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2077 if (editTagsDialog) {
\r
2078 GetWindowPlacement(editTagsDialog, &wp);
\r
2079 editTagsX = wp.rcNormalPosition.left;
\r
2080 editTagsY = wp.rcNormalPosition.top;
\r
2081 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2082 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2085 if (gameListDialog) {
\r
2086 GetWindowPlacement(gameListDialog, &wp);
\r
2087 gameListX = wp.rcNormalPosition.left;
\r
2088 gameListY = wp.rcNormalPosition.top;
\r
2089 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2090 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2093 /* [AS] Move history */
\r
2094 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2096 if( moveHistoryDialog ) {
\r
2097 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2098 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2099 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2100 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2101 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2104 /* [AS] Eval graph */
\r
2105 wpEvalGraph.visible = EvalGraphIsUp();
\r
2107 if( evalGraphDialog ) {
\r
2108 GetWindowPlacement(evalGraphDialog, &wp);
\r
2109 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2110 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2111 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2112 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2115 /* [AS] Engine output */
\r
2116 wpEngineOutput.visible = EngineOutputIsUp();
\r
2118 if( engineOutputDialog ) {
\r
2119 GetWindowPlacement(engineOutputDialog, &wp);
\r
2120 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2121 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2122 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2123 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2126 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2127 if (!ad->save) continue;
\r
2128 switch (ad->argType) {
\r
2131 char *p = *(char **)ad->argLoc;
\r
2132 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2133 /* Quote multiline values or \-containing values
\r
2134 with { } if possible */
\r
2135 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2137 /* Else quote with " " */
\r
2138 fprintf(f, "/%s=\"", ad->argName);
\r
2140 if (*p == '\n') fprintf(f, "\n");
\r
2141 else if (*p == '\r') fprintf(f, "\\r");
\r
2142 else if (*p == '\t') fprintf(f, "\\t");
\r
2143 else if (*p == '\b') fprintf(f, "\\b");
\r
2144 else if (*p == '\f') fprintf(f, "\\f");
\r
2145 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2146 else if (*p == '\"') fprintf(f, "\\\"");
\r
2147 else if (*p == '\\') fprintf(f, "\\\\");
\r
2151 fprintf(f, "\"\n");
\r
2156 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2159 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2162 fprintf(f, "/%s=%s\n", ad->argName,
\r
2163 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2166 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2169 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2173 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2174 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2180 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2181 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2182 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2183 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2184 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2185 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2186 (ta->effects) ? " " : "",
\r
2187 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2191 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2192 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2194 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2197 case ArgBoardSize:
\r
2198 fprintf(f, "/%s=%s\n", ad->argName,
\r
2199 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2204 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2205 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2206 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2207 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2208 ad->argName, mfp->faceName, mfp->pointSize,
\r
2209 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2210 mfp->bold ? "b" : "",
\r
2211 mfp->italic ? "i" : "",
\r
2212 mfp->underline ? "u" : "",
\r
2213 mfp->strikeout ? "s" : "");
\r
2217 case ArgCommSettings:
\r
2218 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2226 /*---------------------------------------------------------------------------*\
\r
2228 * GDI board drawing routines
\r
2230 \*---------------------------------------------------------------------------*/
\r
2232 /* [AS] Draw square using background texture */
\r
2233 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2238 return; /* Should never happen! */
\r
2241 SetGraphicsMode( dst, GM_ADVANCED );
\r
2248 /* X reflection */
\r
2253 x.eDx = (FLOAT) dw + dx - 1;
\r
2256 SetWorldTransform( dst, &x );
\r
2259 /* Y reflection */
\r
2265 x.eDy = (FLOAT) dh + dy - 1;
\r
2267 SetWorldTransform( dst, &x );
\r
2275 x.eDx = (FLOAT) dx;
\r
2276 x.eDy = (FLOAT) dy;
\r
2279 SetWorldTransform( dst, &x );
\r
2283 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2291 SetWorldTransform( dst, &x );
\r
2293 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2296 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2298 PM_WP = (int) WhitePawn,
\r
2299 PM_WN = (int) WhiteKnight,
\r
2300 PM_WB = (int) WhiteBishop,
\r
2301 PM_WR = (int) WhiteRook,
\r
2302 PM_WQ = (int) WhiteQueen,
\r
2304 PM_WF = (int) WhiteFerz,
\r
2305 PM_WW = (int) WhiteWazir,
\r
2306 PM_WE = (int) WhiteAlfil,
\r
2307 PM_WH = (int) WhiteNightrider,
\r
2308 PM_WA = (int) WhiteCardinal,
\r
2309 PM_WC = (int) WhiteMarshall,
\r
2310 PM_WG = (int) WhiteGrasshopper,
\r
2311 PM_WO = (int) WhiteCannon,
\r
2312 PM_WM = (int) WhiteMan,
\r
2313 PM_WU = (int) WhiteUnicorn,
\r
2315 PM_WK = (int) WhiteKing,
\r
2316 PM_BP = (int) BlackPawn,
\r
2317 PM_BN = (int) BlackKnight,
\r
2318 PM_BB = (int) BlackBishop,
\r
2319 PM_BR = (int) BlackRook,
\r
2320 PM_BQ = (int) BlackQueen,
\r
2322 PM_BF = (int) BlackFerz,
\r
2323 PM_BW = (int) BlackWazir,
\r
2324 PM_BE = (int) BlackAlfil,
\r
2325 PM_BH = (int) BlackNightrider,
\r
2326 PM_BA = (int) BlackCardinal,
\r
2327 PM_BC = (int) BlackMarshall,
\r
2328 PM_BG = (int) BlackGrasshopper,
\r
2329 PM_BO = (int) BlackCannon,
\r
2330 PM_BM = (int) BlackMan,
\r
2331 PM_BU = (int) BlackUnicorn,
\r
2333 PM_BK = (int) BlackKing
\r
2336 static HFONT hPieceFont = NULL;
\r
2337 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2338 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2339 static int fontBitmapSquareSize = 0;
\r
2340 static char pieceToFontChar[(int) EmptySquare] =
\r
2341 { 'p', 'n', 'b', 'r', 'q',
\r
2343 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2345 'k', 'o', 'm', 'v', 't', 'w',
\r
2347 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2351 static BOOL SetPieceToFontCharTable( const char * map )
\r
2353 BOOL result = FALSE; int NrPieces;
\r
2355 if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare
\r
2356 && NrPieces >= 12 && !(NrPieces&1)) {
\r
2357 int i; /* [HGM] Accept even length from 12 to 32 */
\r
2359 for( i=0; i<(int) EmptySquare; i++ ) pieceToFontChar[i] = 0;
\r
2360 for( i=0; i<NrPieces/2-1; i++ ) {
\r
2361 pieceToFontChar[i] = map[i];
\r
2362 pieceToFontChar[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];
\r
2364 pieceToFontChar[(int) WhiteKing] = map[NrPieces/2-1];
\r
2365 pieceToFontChar[(int) BlackKing] = map[NrPieces-1];
\r
2373 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2376 BYTE r1 = GetRValue( color );
\r
2377 BYTE g1 = GetGValue( color );
\r
2378 BYTE b1 = GetBValue( color );
\r
2384 /* Create a uniform background first */
\r
2385 hbrush = CreateSolidBrush( color );
\r
2386 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2387 FillRect( hdc, &rc, hbrush );
\r
2388 DeleteObject( hbrush );
\r
2391 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2392 int steps = squareSize / 2;
\r
2395 for( i=0; i<steps; i++ ) {
\r
2396 BYTE r = r1 - (r1-r2) * i / steps;
\r
2397 BYTE g = g1 - (g1-g2) * i / steps;
\r
2398 BYTE b = b1 - (b1-b2) * i / steps;
\r
2400 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2401 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2402 FillRect( hdc, &rc, hbrush );
\r
2403 DeleteObject(hbrush);
\r
2406 else if( mode == 2 ) {
\r
2407 /* Diagonal gradient, good more or less for every piece */
\r
2408 POINT triangle[3];
\r
2409 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2410 HBRUSH hbrush_old;
\r
2411 int steps = squareSize;
\r
2414 triangle[0].x = squareSize - steps;
\r
2415 triangle[0].y = squareSize;
\r
2416 triangle[1].x = squareSize;
\r
2417 triangle[1].y = squareSize;
\r
2418 triangle[2].x = squareSize;
\r
2419 triangle[2].y = squareSize - steps;
\r
2421 for( i=0; i<steps; i++ ) {
\r
2422 BYTE r = r1 - (r1-r2) * i / steps;
\r
2423 BYTE g = g1 - (g1-g2) * i / steps;
\r
2424 BYTE b = b1 - (b1-b2) * i / steps;
\r
2426 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2427 hbrush_old = SelectObject( hdc, hbrush );
\r
2428 Polygon( hdc, triangle, 3 );
\r
2429 SelectObject( hdc, hbrush_old );
\r
2430 DeleteObject(hbrush);
\r
2435 SelectObject( hdc, hpen );
\r
2440 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2441 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2442 piece: follow the steps as explained below.
\r
2444 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2448 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2452 int backColor = whitePieceColor;
\r
2453 int foreColor = blackPieceColor;
\r
2454 int shapeIndex = index < 6 ? index+6 : index;
\r
2456 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2457 backColor = appData.fontBackColorWhite;
\r
2458 foreColor = appData.fontForeColorWhite;
\r
2460 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2461 backColor = appData.fontBackColorBlack;
\r
2462 foreColor = appData.fontForeColorBlack;
\r
2466 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2468 hbm_old = SelectObject( hdc, hbm );
\r
2472 rc.right = squareSize;
\r
2473 rc.bottom = squareSize;
\r
2475 /* Step 1: background is now black */
\r
2476 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2478 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2480 pt.x = (squareSize - sz.cx) / 2;
\r
2481 pt.y = (squareSize - sz.cy) / 2;
\r
2483 SetBkMode( hdc, TRANSPARENT );
\r
2484 SetTextColor( hdc, chroma );
\r
2485 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2486 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2488 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2489 /* Step 3: the area outside the piece is filled with white */
\r
2490 FloodFill( hdc, 0, 0, chroma );
\r
2491 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2493 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2494 but if the start point is not inside the piece we're lost!
\r
2495 There should be a better way to do this... if we could create a region or path
\r
2496 from the fill operation we would be fine for example.
\r
2498 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2500 SetTextColor( hdc, 0 );
\r
2502 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2503 draw the piece again in black for safety.
\r
2505 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2507 SelectObject( hdc, hbm_old );
\r
2509 if( hPieceMask[index] != NULL ) {
\r
2510 DeleteObject( hPieceMask[index] );
\r
2513 hPieceMask[index] = hbm;
\r
2516 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2518 SelectObject( hdc, hbm );
\r
2521 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2522 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2523 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2525 SelectObject( dc1, hPieceMask[index] );
\r
2526 SelectObject( dc2, bm2 );
\r
2527 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2528 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2531 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2532 the piece background and deletes (makes transparent) the rest.
\r
2533 Thanks to that mask, we are free to paint the background with the greates
\r
2534 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2535 We use this, to make gradients and give the pieces a "roundish" look.
\r
2537 SetPieceBackground( hdc, backColor, 2 );
\r
2538 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2542 DeleteObject( bm2 );
\r
2545 SetTextColor( hdc, foreColor );
\r
2546 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2548 SelectObject( hdc, hbm_old );
\r
2550 if( hPieceFace[index] != NULL ) {
\r
2551 DeleteObject( hPieceFace[index] );
\r
2554 hPieceFace[index] = hbm;
\r
2557 static int TranslatePieceToFontPiece( int piece )
\r
2585 case BlackCardinal:
\r
2587 case BlackMarshall:
\r
2591 case BlackNightrider:
\r
2597 case BlackUnicorn:
\r
2601 case BlackGrasshopper:
\r
2605 case WhiteCardinal:
\r
2607 case WhiteMarshall:
\r
2611 case WhiteNightrider:
\r
2617 case WhiteUnicorn:
\r
2621 case WhiteGrasshopper:
\r
2631 void CreatePiecesFromFont()
\r
2634 HDC hdc_window = NULL;
\r
2640 if( fontBitmapSquareSize < 0 ) {
\r
2641 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2645 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2646 fontBitmapSquareSize = -1;
\r
2650 if( fontBitmapSquareSize != squareSize ) {
\r
2651 hdc_window = GetDC( hwndMain );
\r
2652 hdc = CreateCompatibleDC( hdc_window );
\r
2654 if( hPieceFont != NULL ) {
\r
2655 DeleteObject( hPieceFont );
\r
2658 for( i=0; i<12; i++ ) {
\r
2659 hPieceMask[i] = NULL;
\r
2660 hPieceFace[i] = NULL;
\r
2666 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2667 fontHeight = appData.fontPieceSize;
\r
2670 fontHeight = (fontHeight * squareSize) / 100;
\r
2672 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2674 lf.lfEscapement = 0;
\r
2675 lf.lfOrientation = 0;
\r
2676 lf.lfWeight = FW_NORMAL;
\r
2678 lf.lfUnderline = 0;
\r
2679 lf.lfStrikeOut = 0;
\r
2680 lf.lfCharSet = DEFAULT_CHARSET;
\r
2681 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2682 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2683 lf.lfQuality = PROOF_QUALITY;
\r
2684 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2685 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2686 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2688 hPieceFont = CreateFontIndirect( &lf );
\r
2690 if( hPieceFont == NULL ) {
\r
2691 fontBitmapSquareSize = -2;
\r
2694 /* Setup font-to-piece character table */
\r
2695 if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {
\r
2696 /* No (or wrong) global settings, try to detect the font */
\r
2697 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2699 SetPieceToFontCharTable("phbrqkojntwl");
\r
2701 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2702 /* DiagramTT* family */
\r
2703 SetPieceToFontCharTable("PNLRQKpnlrqk");
\r
2706 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2707 /* Fairy symbols */
\r
2708 SetPieceToFontCharTable("PNBRACFHEWUOGMQKpnbracfewuogmqk");
\r
2711 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2712 /* Good Companion (Some characters get warped as literal :-( */
\r
2713 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2714 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2715 SetPieceToFontCharTable(s);
\r
2718 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2719 SetPieceToFontCharTable("pnbrqkomvtwl");
\r
2723 /* Create bitmaps */
\r
2724 hfont_old = SelectObject( hdc, hPieceFont );
\r
2726 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2727 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2728 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2729 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2730 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2731 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2732 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2733 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2734 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2735 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2736 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2737 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2739 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2740 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2741 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2742 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2743 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2744 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2745 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2746 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2747 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2748 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2749 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2750 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2751 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2752 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2753 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2754 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2755 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2756 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2757 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2758 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2761 SelectObject( hdc, hfont_old );
\r
2763 fontBitmapSquareSize = squareSize;
\r
2767 if( hdc != NULL ) {
\r
2771 if( hdc_window != NULL ) {
\r
2772 ReleaseDC( hwndMain, hdc_window );
\r
2777 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2781 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2782 if (gameInfo.event &&
\r
2783 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2784 strcmp(name, "k80s") == 0) {
\r
2785 strcpy(name, "tim");
\r
2787 return LoadBitmap(hinst, name);
\r
2791 /* Insert a color into the program's logical palette
\r
2792 structure. This code assumes the given color is
\r
2793 the result of the RGB or PALETTERGB macro, and it
\r
2794 knows how those macros work (which is documented).
\r
2797 InsertInPalette(COLORREF color)
\r
2799 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2801 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2802 DisplayFatalError("Too many colors", 0, 1);
\r
2803 pLogPal->palNumEntries--;
\r
2807 pe->peFlags = (char) 0;
\r
2808 pe->peRed = (char) (0xFF & color);
\r
2809 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2810 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2816 InitDrawingColors()
\r
2818 if (pLogPal == NULL) {
\r
2819 /* Allocate enough memory for a logical palette with
\r
2820 * PALETTESIZE entries and set the size and version fields
\r
2821 * of the logical palette structure.
\r
2823 pLogPal = (NPLOGPALETTE)
\r
2824 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2825 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2826 pLogPal->palVersion = 0x300;
\r
2828 pLogPal->palNumEntries = 0;
\r
2830 InsertInPalette(lightSquareColor);
\r
2831 InsertInPalette(darkSquareColor);
\r
2832 InsertInPalette(whitePieceColor);
\r
2833 InsertInPalette(blackPieceColor);
\r
2834 InsertInPalette(highlightSquareColor);
\r
2835 InsertInPalette(premoveHighlightColor);
\r
2837 /* create a logical color palette according the information
\r
2838 * in the LOGPALETTE structure.
\r
2840 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2842 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2843 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2844 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2845 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2846 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2847 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2849 /* [AS] Force rendering of the font-based pieces */
\r
2850 if( fontBitmapSquareSize > 0 ) {
\r
2851 fontBitmapSquareSize = 0;
\r
2857 BoardWidth(int boardSize, int n)
\r
2858 { /* [HGM] argument n added to allow different width and height */
\r
2859 int lineGap = sizeInfo[boardSize].lineGap;
\r
2861 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2862 lineGap = appData.overrideLineGap;
\r
2865 return (n + 1) * lineGap +
\r
2866 n * sizeInfo[boardSize].squareSize;
\r
2869 /* Respond to board resize by dragging edge */
\r
2871 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2873 BoardSize newSize = NUM_SIZES - 1;
\r
2874 static int recurse = 0;
\r
2875 if (IsIconic(hwndMain)) return;
\r
2876 if (recurse > 0) return;
\r
2878 while (newSize > 0 &&
\r
2879 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2880 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2883 boardSize = newSize;
\r
2884 InitDrawingSizes(boardSize, flags);
\r
2891 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2893 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2894 ChessSquare piece;
\r
2895 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2897 SIZE clockSize, messageSize;
\r
2899 char buf[MSG_SIZ];
\r
2901 HMENU hmenu = GetMenu(hwndMain);
\r
2902 RECT crect, wrect;
\r
2904 LOGBRUSH logbrush;
\r
2906 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2907 if(boardSize == (BoardSize)(-1) ) boardSize = oldBoardSize;
\r
2909 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2910 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2911 squareSize = sizeInfo[boardSize].squareSize;
\r
2912 lineGap = sizeInfo[boardSize].lineGap;
\r
2914 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2915 lineGap = appData.overrideLineGap;
\r
2918 if (tinyLayout != oldTinyLayout) {
\r
2919 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2921 style &= ~WS_SYSMENU;
\r
2922 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2923 "&Minimize\tCtrl+F4");
\r
2925 style |= WS_SYSMENU;
\r
2926 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2928 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2930 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2931 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2932 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2934 DrawMenuBar(hwndMain);
\r
2937 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2938 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2940 /* Get text area sizes */
\r
2941 hdc = GetDC(hwndMain);
\r
2942 if (appData.clockMode) {
\r
2943 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2945 sprintf(buf, "White");
\r
2947 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2948 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2949 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2950 str = "We only care about the height here";
\r
2951 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2952 SelectObject(hdc, oldFont);
\r
2953 ReleaseDC(hwndMain, hdc);
\r
2955 /* Compute where everything goes */
\r
2956 whiteRect.left = OUTER_MARGIN;
\r
2957 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2958 whiteRect.top = OUTER_MARGIN;
\r
2959 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2961 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2962 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2963 blackRect.top = whiteRect.top;
\r
2964 blackRect.bottom = whiteRect.bottom;
\r
2966 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2967 if (appData.showButtonBar) {
\r
2968 messageRect.right = blackRect.right
\r
2969 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2971 messageRect.right = blackRect.right;
\r
2973 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2974 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2976 boardRect.left = whiteRect.left;
\r
2977 boardRect.right = boardRect.left + boardWidth;
\r
2978 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2979 boardRect.bottom = boardRect.top + boardHeight;
\r
2981 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2982 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2983 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2984 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2985 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2986 GetWindowRect(hwndMain, &wrect);
\r
2987 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2988 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2989 /* compensate if menu bar wrapped */
\r
2990 GetClientRect(hwndMain, &crect);
\r
2991 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2992 winHeight += offby;
\r
2994 case WMSZ_TOPLEFT:
\r
2995 SetWindowPos(hwndMain, NULL,
\r
2996 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2997 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3000 case WMSZ_TOPRIGHT:
\r
3002 SetWindowPos(hwndMain, NULL,
\r
3003 wrect.left, wrect.bottom - winHeight,
\r
3004 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3007 case WMSZ_BOTTOMLEFT:
\r
3009 SetWindowPos(hwndMain, NULL,
\r
3010 wrect.right - winWidth, wrect.top,
\r
3011 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3014 case WMSZ_BOTTOMRIGHT:
\r
3018 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3019 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3024 for (i = 0; i < N_BUTTONS; i++) {
\r
3025 if (buttonDesc[i].hwnd != NULL) {
\r
3026 DestroyWindow(buttonDesc[i].hwnd);
\r
3027 buttonDesc[i].hwnd = NULL;
\r
3029 if (appData.showButtonBar) {
\r
3030 buttonDesc[i].hwnd =
\r
3031 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3032 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3033 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3034 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3035 (HMENU) buttonDesc[i].id,
\r
3036 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3038 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3039 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3040 MAKELPARAM(FALSE, 0));
\r
3042 if (buttonDesc[i].id == IDM_Pause)
\r
3043 hwndPause = buttonDesc[i].hwnd;
\r
3044 buttonDesc[i].wndproc = (WNDPROC)
\r
3045 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3048 if (gridPen != NULL) DeleteObject(gridPen);
\r
3049 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3050 if (premovePen != NULL) DeleteObject(premovePen);
\r
3051 if (lineGap != 0) {
\r
3052 logbrush.lbStyle = BS_SOLID;
\r
3053 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3055 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3056 lineGap, &logbrush, 0, NULL);
\r
3057 logbrush.lbColor = highlightSquareColor;
\r
3059 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3060 lineGap, &logbrush, 0, NULL);
\r
3062 logbrush.lbColor = premoveHighlightColor;
\r
3064 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3065 lineGap, &logbrush, 0, NULL);
\r
3067 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3068 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3069 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3070 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3071 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3072 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3073 BOARD_WIDTH * (squareSize + lineGap);
\r
3074 lineGap / 2 + (i * (squareSize + lineGap));
\r
3075 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3077 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3078 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3079 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3080 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3081 lineGap / 2 + (i * (squareSize + lineGap));
\r
3082 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3083 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3084 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3088 if (boardSize == oldBoardSize) return;
\r
3089 oldBoardSize = boardSize;
\r
3090 oldTinyLayout = tinyLayout;
\r
3092 /* Load piece bitmaps for this board size */
\r
3093 for (i=0; i<=2; i++) {
\r
3094 for (piece = WhitePawn;
\r
3095 (int) piece < (int) BlackPawn;
\r
3096 piece = (ChessSquare) ((int) piece + 1)) {
\r
3097 if (pieceBitmap[i][piece] != NULL)
\r
3098 DeleteObject(pieceBitmap[i][piece]);
\r
3102 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3103 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3104 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3105 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3106 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3107 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3108 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3109 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3110 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3111 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3112 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3113 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3114 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3115 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3116 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3117 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3118 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3119 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3121 if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */
\r
3122 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3123 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3124 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3125 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3126 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3127 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3128 if(!strcmp(appData.variant, "shogi")) { /* promoted Gold represemtations */
\r
3129 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3130 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3131 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3132 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3133 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3134 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3135 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3136 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3137 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3138 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3139 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3140 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3142 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3143 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3144 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3145 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3146 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3147 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3148 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3149 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3150 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3151 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3152 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3153 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3154 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3155 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3156 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3158 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3159 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3160 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3161 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3162 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3163 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3164 if(strcmp(appData.variant, "crazyhouse") && strcmp(appData.variant, "shogi")) {
\r
3165 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3166 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3167 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3169 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3170 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3171 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3173 if(!strcmp(appData.variant, "xiangqi") || !strcmp(appData.variant, "shogi")) {
\r
3174 for(i=0; i<2; i++)
\r
3175 if (pieceBitmap[i][WhiteQueen] != NULL)
\r
3176 DeleteObject(pieceBitmap[i][WhiteQueen]);
\r
3177 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3178 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3179 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3187 PieceBitmap(ChessSquare p, int kind)
\r
3189 if ((int) p >= (int) BlackPawn)
\r
3190 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3192 return pieceBitmap[kind][(int) p];
\r
3195 /***************************************************************/
\r
3197 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3198 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3200 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3201 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3205 SquareToPos(int row, int column, int * x, int * y)
\r
3208 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3209 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3211 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3212 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3217 DrawCoordsOnDC(HDC hdc)
\r
3219 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
3220 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
3221 char str[2] = { NULLCHAR, NULLCHAR };
\r
3222 int oldMode, oldAlign, x, y, start, i;
\r
3226 if (!appData.showCoords)
\r
3229 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3231 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3232 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3233 oldAlign = GetTextAlign(hdc);
\r
3234 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3236 y = boardRect.top + lineGap;
\r
3237 x = boardRect.left + lineGap;
\r
3239 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3240 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3241 str[0] = files[start + i];
\r
3242 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3243 y += squareSize + lineGap;
\r
3246 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3248 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3249 for (i = 0; i < BOARD_WIDTH; i++) {
\r
3250 str[0] = ranks[start + i];
\r
3251 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3252 x += squareSize + lineGap;
\r
3255 SelectObject(hdc, oldBrush);
\r
3256 SetBkMode(hdc, oldMode);
\r
3257 SetTextAlign(hdc, oldAlign);
\r
3258 SelectObject(hdc, oldFont);
\r
3262 DrawGridOnDC(HDC hdc)
\r
3266 if (lineGap != 0) {
\r
3267 oldPen = SelectObject(hdc, gridPen);
\r
3268 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3269 SelectObject(hdc, oldPen);
\r
3273 #define HIGHLIGHT_PEN 0
\r
3274 #define PREMOVE_PEN 1
\r
3277 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3280 HPEN oldPen, hPen;
\r
3281 if (lineGap == 0) return;
\r
3283 x1 = boardRect.left +
\r
3284 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3285 y1 = boardRect.top +
\r
3286 lineGap/2 + y * (squareSize + lineGap);
\r
3288 x1 = boardRect.left +
\r
3289 lineGap/2 + x * (squareSize + lineGap);
\r
3290 y1 = boardRect.top +
\r
3291 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3293 hPen = pen ? premovePen : highlightPen;
\r
3294 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3295 MoveToEx(hdc, x1, y1, NULL);
\r
3296 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3297 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3298 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3299 LineTo(hdc, x1, y1);
\r
3300 SelectObject(hdc, oldPen);
\r
3304 DrawHighlightsOnDC(HDC hdc)
\r
3307 for (i=0; i<2; i++) {
\r
3308 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3309 DrawHighlightOnDC(hdc, TRUE,
\r
3310 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3313 for (i=0; i<2; i++) {
\r
3314 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3315 premoveHighlightInfo.sq[i].y >= 0) {
\r
3316 DrawHighlightOnDC(hdc, TRUE,
\r
3317 premoveHighlightInfo.sq[i].x,
\r
3318 premoveHighlightInfo.sq[i].y,
\r
3324 /* Note: sqcolor is used only in monoMode */
\r
3325 /* Note that this code is largely duplicated in woptions.c,
\r
3326 function DrawSampleSquare, so that needs to be updated too */
\r
3328 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3330 HBITMAP oldBitmap;
\r
3333 if (appData.blindfold) return;
\r
3335 /* [AS] Use font-based pieces if needed */
\r
3336 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3337 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3338 CreatePiecesFromFont();
\r
3340 if( fontBitmapSquareSize == squareSize ) {
\r
3341 int index = TranslatePieceToFontPiece( piece );
\r
3343 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3347 squareSize, squareSize,
\r
3352 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3356 squareSize, squareSize,
\r
3365 if (appData.monoMode) {
\r
3366 SelectObject(tmphdc, PieceBitmap(piece,
\r
3367 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3368 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3369 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3372 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3373 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3374 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3376 /* Use black piece color for outline of white pieces */
\r
3377 /* Not sure this looks really good (though xboard does it).
\r
3378 Maybe better to have another selectable color, default black */
\r
3379 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3380 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3381 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3383 /* Use black for outline of white pieces */
\r
3384 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3385 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);
\r
3389 /* Use white piece color for details of black pieces */
\r
3390 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3391 WHITE_PIECE ones aren't always the right shape. */
\r
3392 /* Not sure this looks really good (though xboard does it).
\r
3393 Maybe better to have another selectable color, default medium gray? */
\r
3394 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3395 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3396 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3397 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3398 SelectObject(hdc, blackPieceBrush);
\r
3399 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3401 /* Use square color for details of black pieces */
\r
3402 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3403 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3404 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);
\r
3407 SelectObject(hdc, oldBrush);
\r
3408 SelectObject(tmphdc, oldBitmap);
\r
3412 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3413 int GetBackTextureMode( int algo )
\r
3415 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3419 case BACK_TEXTURE_MODE_PLAIN:
\r
3420 result = 1; /* Always use identity map */
\r
3422 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3423 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3431 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3432 to handle redraws cleanly (as random numbers would always be different).
\r
3434 VOID RebuildTextureSquareInfo()
\r
3444 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3446 if( liteBackTexture != NULL ) {
\r
3447 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3448 lite_w = bi.bmWidth;
\r
3449 lite_h = bi.bmHeight;
\r
3453 if( darkBackTexture != NULL ) {
\r
3454 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3455 dark_w = bi.bmWidth;
\r
3456 dark_h = bi.bmHeight;
\r
3460 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3461 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3462 if( (col + row) & 1 ) {
\r
3464 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3465 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3466 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3467 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3472 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3473 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3474 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3475 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3482 /* [AS] Arrow highlighting support */
\r
3484 static int A_WIDTH = 5; /* Width of arrow body */
\r
3486 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3487 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3489 static double Sqr( double x )
\r
3494 static int Round( double x )
\r
3496 return (int) (x + 0.5);
\r
3499 /* Draw an arrow between two points using current settings */
\r
3500 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3503 double dx, dy, j, k, x, y;
\r
3505 if( d_x == s_x ) {
\r
3506 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3508 arrow[0].x = s_x + A_WIDTH;
\r
3511 arrow[1].x = s_x + A_WIDTH;
\r
3512 arrow[1].y = d_y - h;
\r
3514 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3515 arrow[2].y = d_y - h;
\r
3520 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3521 arrow[4].y = d_y - h;
\r
3523 arrow[5].x = s_x - A_WIDTH;
\r
3524 arrow[5].y = d_y - h;
\r
3526 arrow[6].x = s_x - A_WIDTH;
\r
3529 else if( d_y == s_y ) {
\r
3530 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3533 arrow[0].y = s_y + A_WIDTH;
\r
3535 arrow[1].x = d_x - w;
\r
3536 arrow[1].y = s_y + A_WIDTH;
\r
3538 arrow[2].x = d_x - w;
\r
3539 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3544 arrow[4].x = d_x - w;
\r
3545 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3547 arrow[5].x = d_x - w;
\r
3548 arrow[5].y = s_y - A_WIDTH;
\r
3551 arrow[6].y = s_y - A_WIDTH;
\r
3554 /* [AS] Needed a lot of paper for this! :-) */
\r
3555 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3556 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3558 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3560 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3565 arrow[0].x = Round(x - j);
\r
3566 arrow[0].y = Round(y + j*dx);
\r
3568 arrow[1].x = Round(x + j);
\r
3569 arrow[1].y = Round(y - j*dx);
\r
3572 x = (double) d_x - k;
\r
3573 y = (double) d_y - k*dy;
\r
3576 x = (double) d_x + k;
\r
3577 y = (double) d_y + k*dy;
\r
3580 arrow[2].x = Round(x + j);
\r
3581 arrow[2].y = Round(y - j*dx);
\r
3583 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3584 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3589 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3590 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3592 arrow[6].x = Round(x - j);
\r
3593 arrow[6].y = Round(y + j*dx);
\r
3596 Polygon( hdc, arrow, 7 );
\r
3599 /* [AS] Draw an arrow between two squares */
\r
3600 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3602 int s_x, s_y, d_x, d_y;
\r
3609 if( s_col == d_col && s_row == d_row ) {
\r
3613 /* Get source and destination points */
\r
3614 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3615 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3618 d_y += squareSize / 4;
\r
3620 else if( d_y < s_y ) {
\r
3621 d_y += 3 * squareSize / 4;
\r
3624 d_y += squareSize / 2;
\r
3628 d_x += squareSize / 4;
\r
3630 else if( d_x < s_x ) {
\r
3631 d_x += 3 * squareSize / 4;
\r
3634 d_x += squareSize / 2;
\r
3637 s_x += squareSize / 2;
\r
3638 s_y += squareSize / 2;
\r
3640 /* Adjust width */
\r
3641 A_WIDTH = squareSize / 14;
\r
3644 stLB.lbStyle = BS_SOLID;
\r
3645 stLB.lbColor = appData.highlightArrowColor;
\r
3648 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3649 holdpen = SelectObject( hdc, hpen );
\r
3650 hbrush = CreateBrushIndirect( &stLB );
\r
3651 holdbrush = SelectObject( hdc, hbrush );
\r
3653 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3655 SelectObject( hdc, holdpen );
\r
3656 SelectObject( hdc, holdbrush );
\r
3657 DeleteObject( hpen );
\r
3658 DeleteObject( hbrush );
\r
3661 BOOL HasHighlightInfo()
\r
3663 BOOL result = FALSE;
\r
3665 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3666 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3674 BOOL IsDrawArrowEnabled()
\r
3676 BOOL result = FALSE;
\r
3678 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3685 VOID DrawArrowHighlight( HDC hdc )
\r
3687 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3688 DrawArrowBetweenSquares( hdc,
\r
3689 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3690 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3694 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3696 HRGN result = NULL;
\r
3698 if( HasHighlightInfo() ) {
\r
3699 int x1, y1, x2, y2;
\r
3700 int sx, sy, dx, dy;
\r
3702 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3703 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3705 sx = MIN( x1, x2 );
\r
3706 sy = MIN( y1, y2 );
\r
3707 dx = MAX( x1, x2 ) + squareSize;
\r
3708 dy = MAX( y1, y2 ) + squareSize;
\r
3710 result = CreateRectRgn( sx, sy, dx, dy );
\r
3717 Warning: this function modifies the behavior of several other functions.
\r
3719 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3720 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3721 repaint is scattered all over the place, which is not good for features such as
\r
3722 "arrow highlighting" that require a full repaint of the board.
\r
3724 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3725 user interaction, when speed is not so important) but especially to avoid errors
\r
3726 in the displayed graphics.
\r
3728 In such patched places, I always try refer to this function so there is a single
\r
3729 place to maintain knowledge.
\r
3731 To restore the original behavior, just return FALSE unconditionally.
\r
3733 BOOL IsFullRepaintPreferrable()
\r
3735 BOOL result = FALSE;
\r
3737 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3738 /* Arrow may appear on the board */
\r
3746 This function is called by DrawPosition to know whether a full repaint must
\r
3749 Only DrawPosition may directly call this function, which makes use of
\r
3750 some state information. Other function should call DrawPosition specifying
\r
3751 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3753 BOOL DrawPositionNeedsFullRepaint()
\r
3755 BOOL result = FALSE;
\r
3758 Probably a slightly better policy would be to trigger a full repaint
\r
3759 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3760 but animation is fast enough that it's difficult to notice.
\r
3762 if( animInfo.piece == EmptySquare ) {
\r
3763 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3772 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3774 int row, column, x, y, square_color, piece_color;
\r
3775 ChessSquare piece;
\r
3777 HDC texture_hdc = NULL;
\r
3779 /* [AS] Initialize background textures if needed */
\r
3780 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3781 if( backTextureSquareSize != squareSize ) {
\r
3782 backTextureSquareSize = squareSize;
\r
3783 RebuildTextureSquareInfo();
\r
3786 texture_hdc = CreateCompatibleDC( hdc );
\r
3789 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3790 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3792 SquareToPos(row, column, &x, &y);
\r
3794 piece = board[row][column];
\r
3796 square_color = ((column + row) % 2) == 1;
\r
3797 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3798 square_color = !InPalace(row, column);
\r
3799 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3800 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3802 piece_color = (int) piece < (int) BlackPawn;
\r
3806 /* [HGM] holdings file: light square or black */
\r
3807 if(column == BOARD_LEFT-2) {
\r
3808 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3811 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3815 if(column == BOARD_RGHT + 1 ) {
\r
3816 if( row < gameInfo.holdingsSize )
\r
3819 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3823 if(column == BOARD_LEFT-1 ) /* left align */
\r
3824 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3825 else if( column == BOARD_RGHT) /* right align */
\r
3826 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3829 if (appData.monoMode) {
\r
3830 if (piece == EmptySquare) {
\r
3831 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3832 square_color ? WHITENESS : BLACKNESS);
\r
3834 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3837 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3838 /* [AS] Draw the square using a texture bitmap */
\r
3839 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3842 squareSize, squareSize,
\r
3845 backTextureSquareInfo[row][column].mode,
\r
3846 backTextureSquareInfo[row][column].x,
\r
3847 backTextureSquareInfo[row][column].y );
\r
3849 SelectObject( texture_hdc, hbm );
\r
3851 if (piece != EmptySquare) {
\r
3852 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3856 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3858 oldBrush = SelectObject(hdc, brush );
\r
3859 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3860 SelectObject(hdc, oldBrush);
\r
3861 if (piece != EmptySquare)
\r
3862 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3867 if( texture_hdc != NULL ) {
\r
3868 DeleteDC( texture_hdc );
\r
3872 #define MAX_CLIPS 200 /* more than enough */
\r
3875 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3877 static Board lastReq, lastDrawn;
\r
3878 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3879 static int lastDrawnFlipView = 0;
\r
3880 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3881 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3884 HBITMAP bufferBitmap;
\r
3885 HBITMAP oldBitmap;
\r
3887 HRGN clips[MAX_CLIPS];
\r
3888 ChessSquare dragged_piece = EmptySquare;
\r
3890 /* I'm undecided on this - this function figures out whether a full
\r
3891 * repaint is necessary on its own, so there's no real reason to have the
\r
3892 * caller tell it that. I think this can safely be set to FALSE - but
\r
3893 * if we trust the callers not to request full repaints unnessesarily, then
\r
3894 * we could skip some clipping work. In other words, only request a full
\r
3895 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3896 * gamestart and similar) --Hawk
\r
3898 Boolean fullrepaint = repaint;
\r
3900 if( DrawPositionNeedsFullRepaint() ) {
\r
3901 fullrepaint = TRUE;
\r
3905 if( fullrepaint ) {
\r
3906 static int repaint_count = 0;
\r
3910 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
3911 OutputDebugString( buf );
\r
3915 if (board == NULL) {
\r
3916 if (!lastReqValid) {
\r
3921 CopyBoard(lastReq, board);
\r
3925 if (doingSizing) {
\r
3929 if (IsIconic(hwndMain)) {
\r
3933 if (hdc == NULL) {
\r
3934 hdc = GetDC(hwndMain);
\r
3935 if (!appData.monoMode) {
\r
3936 SelectPalette(hdc, hPal, FALSE);
\r
3937 RealizePalette(hdc);
\r
3941 releaseDC = FALSE;
\r
3945 fprintf(debugFP, "*******************************\n"
\r
3947 "dragInfo.from (%d,%d)\n"
\r
3948 "dragInfo.start (%d,%d)\n"
\r
3949 "dragInfo.pos (%d,%d)\n"
\r
3950 "dragInfo.lastpos (%d,%d)\n",
\r
3951 repaint ? "TRUE" : "FALSE",
\r
3952 dragInfo.from.x, dragInfo.from.y,
\r
3953 dragInfo.start.x, dragInfo.start.y,
\r
3954 dragInfo.pos.x, dragInfo.pos.y,
\r
3955 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3956 fprintf(debugFP, "prev: ");
\r
3957 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3958 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3959 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3962 fprintf(debugFP, "\n");
\r
3963 fprintf(debugFP, "board: ");
\r
3964 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3965 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3966 fprintf(debugFP, "%d ", board[row][column]);
\r
3969 fprintf(debugFP, "\n");
\r
3973 /* Create some work-DCs */
\r
3974 hdcmem = CreateCompatibleDC(hdc);
\r
3975 tmphdc = CreateCompatibleDC(hdc);
\r
3977 /* If dragging is in progress, we temporarely remove the piece */
\r
3978 /* [HGM] or temporarily decrease count if stacked */
\r
3979 /* !! Moved to before board compare !! */
\r
3980 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3981 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3982 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3983 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3984 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3986 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3987 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
3988 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3990 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3993 /* Figure out which squares need updating by comparing the
\r
3994 * newest board with the last drawn board and checking if
\r
3995 * flipping has changed.
\r
3997 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
3998 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
3999 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4000 if (lastDrawn[row][column] != board[row][column]) {
\r
4001 SquareToPos(row, column, &x, &y);
\r
4002 clips[num_clips++] =
\r
4003 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4007 for (i=0; i<2; i++) {
\r
4008 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4009 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4010 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4011 lastDrawnHighlight.sq[i].y >= 0) {
\r
4012 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4013 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4014 clips[num_clips++] =
\r
4015 CreateRectRgn(x - lineGap, y - lineGap,
\r
4016 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4018 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4019 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4020 clips[num_clips++] =
\r
4021 CreateRectRgn(x - lineGap, y - lineGap,
\r
4022 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4026 for (i=0; i<2; i++) {
\r
4027 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4028 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4029 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4030 lastDrawnPremove.sq[i].y >= 0) {
\r
4031 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4032 lastDrawnPremove.sq[i].x, &x, &y);
\r
4033 clips[num_clips++] =
\r
4034 CreateRectRgn(x - lineGap, y - lineGap,
\r
4035 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4037 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4038 premoveHighlightInfo.sq[i].y >= 0) {
\r
4039 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4040 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4041 clips[num_clips++] =
\r
4042 CreateRectRgn(x - lineGap, y - lineGap,
\r
4043 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4048 fullrepaint = TRUE;
\r
4051 /* Create a buffer bitmap - this is the actual bitmap
\r
4052 * being written to. When all the work is done, we can
\r
4053 * copy it to the real DC (the screen). This avoids
\r
4054 * the problems with flickering.
\r
4056 GetClientRect(hwndMain, &Rect);
\r
4057 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4058 Rect.bottom-Rect.top+1);
\r
4059 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4060 if (!appData.monoMode) {
\r
4061 SelectPalette(hdcmem, hPal, FALSE);
\r
4064 /* Create clips for dragging */
\r
4065 if (!fullrepaint) {
\r
4066 if (dragInfo.from.x >= 0) {
\r
4067 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4068 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4070 if (dragInfo.start.x >= 0) {
\r
4071 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4072 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4074 if (dragInfo.pos.x >= 0) {
\r
4075 x = dragInfo.pos.x - squareSize / 2;
\r
4076 y = dragInfo.pos.y - squareSize / 2;
\r
4077 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4079 if (dragInfo.lastpos.x >= 0) {
\r
4080 x = dragInfo.lastpos.x - squareSize / 2;
\r
4081 y = dragInfo.lastpos.y - squareSize / 2;
\r
4082 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4086 /* Are we animating a move?
\r
4088 * - remove the piece from the board (temporarely)
\r
4089 * - calculate the clipping region
\r
4091 if (!fullrepaint) {
\r
4092 if (animInfo.piece != EmptySquare) {
\r
4093 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4094 x = boardRect.left + animInfo.lastpos.x;
\r
4095 y = boardRect.top + animInfo.lastpos.y;
\r
4096 x2 = boardRect.left + animInfo.pos.x;
\r
4097 y2 = boardRect.top + animInfo.pos.y;
\r
4098 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4099 /* Slight kludge. The real problem is that after AnimateMove is
\r
4100 done, the position on the screen does not match lastDrawn.
\r
4101 This currently causes trouble only on e.p. captures in
\r
4102 atomic, where the piece moves to an empty square and then
\r
4103 explodes. The old and new positions both had an empty square
\r
4104 at the destination, but animation has drawn a piece there and
\r
4105 we have to remember to erase it. */
\r
4106 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4110 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4111 if (num_clips == 0)
\r
4112 fullrepaint = TRUE;
\r
4114 /* Set clipping on the memory DC */
\r
4115 if (!fullrepaint) {
\r
4116 SelectClipRgn(hdcmem, clips[0]);
\r
4117 for (x = 1; x < num_clips; x++) {
\r
4118 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4119 abort(); // this should never ever happen!
\r
4123 /* Do all the drawing to the memory DC */
\r
4124 DrawGridOnDC(hdcmem);
\r
4125 DrawHighlightsOnDC(hdcmem);
\r
4126 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4128 if( appData.highlightMoveWithArrow ) {
\r
4129 DrawArrowHighlight(hdcmem);
\r
4132 DrawCoordsOnDC(hdcmem);
\r
4134 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4135 /* to make sure lastDrawn contains what is actually drawn */
\r
4137 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4138 if (dragged_piece != EmptySquare) {
\r
4139 /* [HGM] or restack */
\r
4140 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4141 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4143 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4144 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4145 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4146 x = dragInfo.pos.x - squareSize / 2;
\r
4147 y = dragInfo.pos.y - squareSize / 2;
\r
4148 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4149 ((int) dragged_piece < (int) BlackPawn),
\r
4150 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4153 /* Put the animated piece back into place and draw it */
\r
4154 if (animInfo.piece != EmptySquare) {
\r
4155 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4156 x = boardRect.left + animInfo.pos.x;
\r
4157 y = boardRect.top + animInfo.pos.y;
\r
4158 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4159 ((int) animInfo.piece < (int) BlackPawn),
\r
4160 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4163 /* Release the bufferBitmap by selecting in the old bitmap
\r
4164 * and delete the memory DC
\r
4166 SelectObject(hdcmem, oldBitmap);
\r
4169 /* Set clipping on the target DC */
\r
4170 if (!fullrepaint) {
\r
4171 SelectClipRgn(hdc, clips[0]);
\r
4172 for (x = 1; x < num_clips; x++) {
\r
4173 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4174 abort(); // this should never ever happen!
\r
4178 /* Copy the new bitmap onto the screen in one go.
\r
4179 * This way we avoid any flickering
\r
4181 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4182 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4183 boardRect.right - boardRect.left,
\r
4184 boardRect.bottom - boardRect.top,
\r
4185 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4186 SelectObject(tmphdc, oldBitmap);
\r
4188 /* Massive cleanup */
\r
4189 for (x = 0; x < num_clips; x++)
\r
4190 DeleteObject(clips[x]);
\r
4193 DeleteObject(bufferBitmap);
\r
4196 ReleaseDC(hwndMain, hdc);
\r
4198 if (lastDrawnFlipView != flipView) {
\r
4200 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4202 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4205 /* CopyBoard(lastDrawn, board);*/
\r
4206 lastDrawnHighlight = highlightInfo;
\r
4207 lastDrawnPremove = premoveHighlightInfo;
\r
4208 lastDrawnFlipView = flipView;
\r
4209 lastDrawnValid = 1;
\r
4213 /*---------------------------------------------------------------------------*\
\r
4214 | CLIENT PAINT PROCEDURE
\r
4215 | This is the main event-handler for the WM_PAINT message.
\r
4217 \*---------------------------------------------------------------------------*/
\r
4219 PaintProc(HWND hwnd)
\r
4225 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4226 if (IsIconic(hwnd)) {
\r
4227 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4229 if (!appData.monoMode) {
\r
4230 SelectPalette(hdc, hPal, FALSE);
\r
4231 RealizePalette(hdc);
\r
4233 HDCDrawPosition(hdc, 1, NULL);
\r
4235 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4236 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4237 ETO_CLIPPED|ETO_OPAQUE,
\r
4238 &messageRect, messageText, strlen(messageText), NULL);
\r
4239 SelectObject(hdc, oldFont);
\r
4240 DisplayBothClocks();
\r
4242 EndPaint(hwnd,&ps);
\r
4250 * If the user selects on a border boundary, return -1; if off the board,
\r
4251 * return -2. Otherwise map the event coordinate to the square.
\r
4252 * The offset boardRect.left or boardRect.top must already have been
\r
4253 * subtracted from x.
\r
4256 EventToSquare(int x)
\r
4263 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4265 x /= (squareSize + lineGap);
\r
4266 if (x >= BOARD_SIZE)
\r
4277 DropEnable dropEnables[] = {
\r
4278 { 'P', DP_Pawn, "Pawn" },
\r
4279 { 'N', DP_Knight, "Knight" },
\r
4280 { 'B', DP_Bishop, "Bishop" },
\r
4281 { 'R', DP_Rook, "Rook" },
\r
4282 { 'Q', DP_Queen, "Queen" },
\r
4286 SetupDropMenu(HMENU hmenu)
\r
4288 int i, count, enable;
\r
4290 extern char white_holding[], black_holding[];
\r
4291 char item[MSG_SIZ];
\r
4293 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4294 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4295 dropEnables[i].piece);
\r
4297 while (p && *p++ == dropEnables[i].piece) count++;
\r
4298 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4299 enable = count > 0 || !appData.testLegality
\r
4300 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4301 && !appData.icsActive);
\r
4302 ModifyMenu(hmenu, dropEnables[i].command,
\r
4303 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4304 dropEnables[i].command, item);
\r
4308 static int fromX = -1, fromY = -1, toX, toY;
\r
4310 /* Event handler for mouse messages */
\r
4312 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4316 static int recursive = 0;
\r
4318 BOOLEAN needsRedraw = FALSE;
\r
4319 BOOLEAN saveAnimate;
\r
4320 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4321 static BOOLEAN sameAgain = FALSE;
\r
4322 ChessMove moveType;
\r
4325 if (message == WM_MBUTTONUP) {
\r
4326 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4327 to the middle button: we simulate pressing the left button too!
\r
4329 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4330 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4336 pt.x = LOWORD(lParam);
\r
4337 pt.y = HIWORD(lParam);
\r
4338 x = EventToSquare(pt.x - boardRect.left);
\r
4339 y = EventToSquare(pt.y - boardRect.top);
\r
4340 if (!flipView && y >= 0) {
\r
4341 y = BOARD_HEIGHT - 1 - y;
\r
4343 if (flipView && x >= 0) {
\r
4344 x = BOARD_WIDTH - 1 - x;
\r
4347 switch (message) {
\r
4348 case WM_LBUTTONDOWN:
\r
4350 sameAgain = FALSE;
\r
4352 /* Downclick vertically off board; check if on clock */
\r
4353 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4354 if (gameMode == EditPosition) {
\r
4355 SetWhiteToPlayEvent();
\r
4356 } else if (gameMode == IcsPlayingBlack ||
\r
4357 gameMode == MachinePlaysWhite) {
\r
4360 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4361 if (gameMode == EditPosition) {
\r
4362 SetBlackToPlayEvent();
\r
4363 } else if (gameMode == IcsPlayingWhite ||
\r
4364 gameMode == MachinePlaysBlack) {
\r
4368 if (!appData.highlightLastMove) {
\r
4369 ClearHighlights();
\r
4370 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4372 fromX = fromY = -1;
\r
4373 dragInfo.start.x = dragInfo.start.y = -1;
\r
4374 dragInfo.from = dragInfo.start;
\r
4376 } else if (x < 0 || y < 0
\r
4377 /* [HGM] block clicks between board and holdings */
\r
4378 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4379 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4380 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4383 } else if (fromX == x && fromY == y) {
\r
4384 /* Downclick on same square again */
\r
4385 ClearHighlights();
\r
4386 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4387 sameAgain = TRUE;
\r
4388 } else if (fromX != -1 &&
\r
4389 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4391 /* Downclick on different square. */
\r
4392 /* [HGM] if on holdings file, should count as new first click ! */
\r
4394 ChessSquare pdown, pup;
\r
4395 pdown = boards[currentMove][fromY][fromX];
\r
4396 pup = boards[currentMove][y][x];
\r
4397 if (gameMode == EditPosition || /* [HGM] max piece > King! */
\r
4398 !((WhitePawn <= pdown && pdown < BlackPawn &&
\r
4399 WhitePawn <= pup && pup < BlackPawn) ||
\r
4400 (BlackPawn <= pdown && pdown < EmptySquare &&
\r
4401 BlackPawn <= pup && pup < EmptySquare))) {
\r
4402 /* EditPosition, empty square, or different color piece;
\r
4403 click-click move is possible */
\r
4406 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4407 if(moveType != ImpossibleMove) {
\r
4408 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4409 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4410 to make sure move is legal before showing promotion popup */
\r
4411 if (appData.alwaysPromoteToQueen) {
\r
4412 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4413 if (!appData.highlightLastMove) {
\r
4414 ClearHighlights();
\r
4415 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4418 SetHighlights(fromX, fromY, toX, toY);
\r
4419 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4420 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4421 If promotion to Q is legal, all are legal! */
\r
4422 PromotionPopup(hwnd);
\r
4424 } else { /* not a promotion */
\r
4425 if (appData.animate || appData.highlightLastMove) {
\r
4426 SetHighlights(fromX, fromY, toX, toY);
\r
4428 ClearHighlights();
\r
4430 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4431 if (appData.animate && !appData.highlightLastMove) {
\r
4432 ClearHighlights();
\r
4433 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4437 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4438 fromX = fromY = -1;
\r
4441 ClearHighlights();
\r
4442 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4444 /* First downclick, or restart on a square with same color piece */
\r
4445 if (!frozen && OKToStartUserMove(x, y)) {
\r
4448 dragInfo.lastpos = pt;
\r
4449 dragInfo.from.x = fromX;
\r
4450 dragInfo.from.y = fromY;
\r
4451 dragInfo.start = dragInfo.from;
\r
4452 SetCapture(hwndMain);
\r
4454 fromX = fromY = -1;
\r
4455 dragInfo.start.x = dragInfo.start.y = -1;
\r
4456 dragInfo.from = dragInfo.start;
\r
4457 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4461 case WM_LBUTTONUP:
\r
4463 if (fromX == -1) break;
\r
4464 if (x == fromX && y == fromY) {
\r
4465 /* Upclick on same square */
\r
4467 /* Clicked same square twice: abort click-click move */
\r
4468 fromX = fromY = -1;
\r
4470 ClearPremoveHighlights();
\r
4472 /* First square clicked: start click-click move */
\r
4473 SetHighlights(fromX, fromY, -1, -1);
\r
4475 dragInfo.from.x = dragInfo.from.y = -1;
\r
4476 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4477 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4478 /* Errant click; ignore */
\r
4481 /* Finish drag move. */
\r
4482 if (appData.debugMode) {
\r
4483 fprintf(debugFP, "release\n");
\r
4485 dragInfo.from.x = dragInfo.from.y = -1;
\r
4488 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4489 appData.animate = appData.animate && !appData.animateDragging;
\r
4490 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4491 if(moveType != ImpossibleMove) {
\r
4492 if (IsPromotion(fromX, fromY, toX, toY)) {
\r
4493 if (appData.alwaysPromoteToQueen)
\r
4494 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4496 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4497 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4499 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4501 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4502 appData.animate = saveAnimate;
\r
4503 fromX = fromY = -1;
\r
4504 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4505 ClearHighlights();
\r
4507 if (appData.animate || appData.animateDragging ||
\r
4508 appData.highlightDragging || gotPremove) {
\r
4509 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4512 dragInfo.start.x = dragInfo.start.y = -1;
\r
4513 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4516 case WM_MOUSEMOVE:
\r
4517 if ((appData.animateDragging || appData.highlightDragging)
\r
4518 && (wParam & MK_LBUTTON)
\r
4519 && dragInfo.from.x >= 0)
\r
4521 BOOL full_repaint = FALSE;
\r
4523 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4524 if (appData.animateDragging) {
\r
4525 dragInfo.pos = pt;
\r
4527 if (appData.highlightDragging) {
\r
4528 SetHighlights(fromX, fromY, x, y);
\r
4529 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4530 full_repaint = TRUE;
\r
4534 DrawPosition( full_repaint, NULL);
\r
4536 dragInfo.lastpos = dragInfo.pos;
\r
4540 case WM_MBUTTONDOWN:
\r
4541 case WM_RBUTTONDOWN:
\r
4544 fromX = fromY = -1;
\r
4545 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4546 dragInfo.start.x = dragInfo.start.y = -1;
\r
4547 dragInfo.from = dragInfo.start;
\r
4548 dragInfo.lastpos = dragInfo.pos;
\r
4549 if (appData.highlightDragging) {
\r
4550 ClearHighlights();
\r
4552 DrawPosition(TRUE, NULL);
\r
4554 switch (gameMode) {
\r
4555 case EditPosition:
\r
4556 case IcsExamining:
\r
4557 if (x < 0 || y < 0) break;
\r
4560 if (message == WM_MBUTTONDOWN) {
\r
4561 buttonCount = 3; /* even if system didn't think so */
\r
4562 if (wParam & MK_SHIFT)
\r
4563 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4565 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4566 } else { /* message == WM_RBUTTONDOWN */
\r
4568 if (buttonCount == 3) {
\r
4569 if (wParam & MK_SHIFT)
\r
4570 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4572 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4574 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4577 /* Just have one menu, on the right button. Windows users don't
\r
4578 think to try the middle one, and sometimes other software steals
\r
4579 it, or it doesn't really exist. */
\r
4580 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4584 case IcsPlayingWhite:
\r
4585 case IcsPlayingBlack:
\r
4587 case MachinePlaysWhite:
\r
4588 case MachinePlaysBlack:
\r
4589 if (appData.testLegality &&
\r
4590 gameInfo.variant != VariantBughouse &&
\r
4591 gameInfo.variant != VariantCrazyhouse) break;
\r
4592 if (x < 0 || y < 0) break;
\r
4595 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4596 SetupDropMenu(hmenu);
\r
4597 MenuPopup(hwnd, pt, hmenu, -1);
\r
4608 /* Preprocess messages for buttons in main window */
\r
4610 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4612 int id = GetWindowLong(hwnd, GWL_ID);
\r
4615 for (i=0; i<N_BUTTONS; i++) {
\r
4616 if (buttonDesc[i].id == id) break;
\r
4618 if (i == N_BUTTONS) return 0;
\r
4619 switch (message) {
\r
4624 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4625 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4632 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4635 if (appData.icsActive) {
\r
4636 if (GetKeyState(VK_SHIFT) < 0) {
\r
4638 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4639 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4643 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4644 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4651 if (appData.icsActive) {
\r
4652 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4653 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4655 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4657 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4658 PopUpMoveDialog((char)wParam);
\r
4664 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4667 /* Process messages for Promotion dialog box */
\r
4669 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4673 switch (message) {
\r
4674 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4675 /* Center the dialog over the application window */
\r
4676 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4677 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4678 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4679 gameInfo.variant == VariantGiveaway) ?
\r
4680 SW_SHOW : SW_HIDE);
\r
4682 /* [HGM] Only allow C & A promotions in Capablanca Chess */
\r
4683 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4684 (gameInfo.variant == VariantCapablanca ||
\r
4685 gameInfo.variant == VariantGothic) ?
\r
4686 SW_SHOW : SW_HIDE);
\r
4687 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4688 (gameInfo.variant == VariantCapablanca ||
\r
4689 gameInfo.variant == VariantGothic) ?
\r
4690 SW_SHOW : SW_HIDE);
\r
4694 case WM_COMMAND: /* message: received a command */
\r
4695 switch (LOWORD(wParam)) {
\r
4697 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4698 ClearHighlights();
\r
4699 DrawPosition(FALSE, NULL);
\r
4714 case PB_Chancellor:
\r
4717 case PB_Archbishop:
\r
4727 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4728 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4729 only show the popup when we are already sure the move is valid or
\r
4730 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4731 will figure out it is a promotion from the promoChar. */
\r
4732 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
4733 if (!appData.highlightLastMove) {
\r
4734 ClearHighlights();
\r
4735 DrawPosition(FALSE, NULL);
\r
4742 /* Pop up promotion dialog */
\r
4744 PromotionPopup(HWND hwnd)
\r
4748 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4749 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4750 hwnd, (DLGPROC)lpProc);
\r
4751 FreeProcInstance(lpProc);
\r
4754 /* Toggle ShowThinking */
\r
4756 ToggleShowThinking()
\r
4758 ShowThinkingEvent(!appData.showThinking);
\r
4762 LoadGameDialog(HWND hwnd, char* title)
\r
4766 char fileTitle[MSG_SIZ];
\r
4767 f = OpenFileDialog(hwnd, FALSE, "",
\r
4768 appData.oldSaveStyle ? "gam" : "pgn",
\r
4770 title, &number, fileTitle, NULL);
\r
4772 cmailMsgLoaded = FALSE;
\r
4773 if (number == 0) {
\r
4774 int error = GameListBuild(f);
\r
4776 DisplayError("Cannot build game list", error);
\r
4777 } else if (!ListEmpty(&gameList) &&
\r
4778 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4779 GameListPopUp(f, fileTitle);
\r
4782 GameListDestroy();
\r
4785 LoadGame(f, number, fileTitle, FALSE);
\r
4790 ChangedConsoleFont()
\r
4793 CHARRANGE tmpsel, sel;
\r
4794 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4795 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4796 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4799 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4800 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4801 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4802 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4803 * size. This was undocumented in the version of MSVC++ that I had
\r
4804 * when I wrote the code, but is apparently documented now.
\r
4806 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4807 cfmt.bCharSet = f->lf.lfCharSet;
\r
4808 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4809 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4810 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4811 /* Why are the following seemingly needed too? */
\r
4812 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4813 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4814 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4816 tmpsel.cpMax = -1; /*999999?*/
\r
4817 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4818 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4819 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4820 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4822 paraf.cbSize = sizeof(paraf);
\r
4823 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4824 paraf.dxStartIndent = 0;
\r
4825 paraf.dxOffset = WRAP_INDENT;
\r
4826 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4827 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4830 /*---------------------------------------------------------------------------*\
\r
4832 * Window Proc for main window
\r
4834 \*---------------------------------------------------------------------------*/
\r
4836 /* Process messages for main window, etc. */
\r
4838 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4841 int wmId, wmEvent;
\r
4845 char fileTitle[MSG_SIZ];
\r
4846 static SnapData sd;
\r
4848 switch (message) {
\r
4850 case WM_PAINT: /* message: repaint portion of window */
\r
4854 case WM_ERASEBKGND:
\r
4855 if (IsIconic(hwnd)) {
\r
4856 /* Cheat; change the message */
\r
4857 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4859 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4863 case WM_LBUTTONDOWN:
\r
4864 case WM_MBUTTONDOWN:
\r
4865 case WM_RBUTTONDOWN:
\r
4866 case WM_LBUTTONUP:
\r
4867 case WM_MBUTTONUP:
\r
4868 case WM_RBUTTONUP:
\r
4869 case WM_MOUSEMOVE:
\r
4870 MouseEvent(hwnd, message, wParam, lParam);
\r
4875 if (appData.icsActive) {
\r
4876 if (wParam == '\t') {
\r
4877 if (GetKeyState(VK_SHIFT) < 0) {
\r
4879 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4880 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4884 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4885 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4889 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4890 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4892 SendMessage(h, message, wParam, lParam);
\r
4894 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4895 PopUpMoveDialog((char)wParam);
\r
4899 case WM_PALETTECHANGED:
\r
4900 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4902 HDC hdc = GetDC(hwndMain);
\r
4903 SelectPalette(hdc, hPal, TRUE);
\r
4904 nnew = RealizePalette(hdc);
\r
4906 paletteChanged = TRUE;
\r
4908 UpdateColors(hdc);
\r
4910 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4913 ReleaseDC(hwnd, hdc);
\r
4917 case WM_QUERYNEWPALETTE:
\r
4918 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4920 HDC hdc = GetDC(hwndMain);
\r
4921 paletteChanged = FALSE;
\r
4922 SelectPalette(hdc, hPal, FALSE);
\r
4923 nnew = RealizePalette(hdc);
\r
4925 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4927 ReleaseDC(hwnd, hdc);
\r
4932 case WM_COMMAND: /* message: command from application menu */
\r
4933 wmId = LOWORD(wParam);
\r
4934 wmEvent = HIWORD(wParam);
\r
4939 AnalysisPopDown();
\r
4942 case IDM_NewGameFRC:
\r
4943 if( NewGameFRC() == 0 ) {
\r
4945 AnalysisPopDown();
\r
4949 case IDM_NewVariant:
\r
4950 NewVariantPopup(hwnd);
\r
4953 case IDM_LoadGame:
\r
4954 LoadGameDialog(hwnd, "Load Game from File");
\r
4957 case IDM_LoadNextGame:
\r
4961 case IDM_LoadPrevGame:
\r
4965 case IDM_ReloadGame:
\r
4969 case IDM_LoadPosition:
\r
4970 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
4971 Reset(FALSE, TRUE);
\r
4974 f = OpenFileDialog(hwnd, FALSE, "",
\r
4975 appData.oldSaveStyle ? "pos" : "fen",
\r
4977 "Load Position from File", &number, fileTitle, NULL);
\r
4979 LoadPosition(f, number, fileTitle);
\r
4983 case IDM_LoadNextPosition:
\r
4984 ReloadPosition(1);
\r
4987 case IDM_LoadPrevPosition:
\r
4988 ReloadPosition(-1);
\r
4991 case IDM_ReloadPosition:
\r
4992 ReloadPosition(0);
\r
4995 case IDM_SaveGame:
\r
4996 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
4997 f = OpenFileDialog(hwnd, TRUE, defName,
\r
4998 appData.oldSaveStyle ? "gam" : "pgn",
\r
5000 "Save Game to File", NULL, fileTitle, NULL);
\r
5002 SaveGame(f, 0, "");
\r
5006 case IDM_SavePosition:
\r
5007 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5008 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5009 appData.oldSaveStyle ? "pos" : "fen",
\r
5011 "Save Position to File", NULL, fileTitle, NULL);
\r
5013 SavePosition(f, 0, "");
\r
5017 case IDM_CopyGame:
\r
5018 CopyGameToClipboard();
\r
5021 case IDM_PasteGame:
\r
5022 PasteGameFromClipboard();
\r
5025 case IDM_CopyGameListToClipboard:
\r
5026 CopyGameListToClipboard();
\r
5029 /* [AS] Autodetect FEN or PGN data */
\r
5030 case IDM_PasteAny:
\r
5031 PasteGameOrFENFromClipboard();
\r
5034 /* [AS] Move history */
\r
5035 case IDM_ShowMoveHistory:
\r
5036 if( MoveHistoryIsUp() ) {
\r
5037 MoveHistoryPopDown();
\r
5040 MoveHistoryPopUp();
\r
5044 /* [AS] Eval graph */
\r
5045 case IDM_ShowEvalGraph:
\r
5046 if( EvalGraphIsUp() ) {
\r
5047 EvalGraphPopDown();
\r
5054 /* [AS] Engine output */
\r
5055 case IDM_ShowEngineOutput:
\r
5056 if( EngineOutputIsUp() ) {
\r
5057 EngineOutputPopDown();
\r
5060 EngineOutputPopUp();
\r
5064 /* [AS] User adjudication */
\r
5065 case IDM_UserAdjudication_White:
\r
5066 UserAdjudicationEvent( +1 );
\r
5069 case IDM_UserAdjudication_Black:
\r
5070 UserAdjudicationEvent( -1 );
\r
5073 case IDM_UserAdjudication_Draw:
\r
5074 UserAdjudicationEvent( 0 );
\r
5077 /* [AS] Game list options dialog */
\r
5078 case IDM_GameListOptions:
\r
5079 GameListOptions();
\r
5082 case IDM_CopyPosition:
\r
5083 CopyFENToClipboard();
\r
5086 case IDM_PastePosition:
\r
5087 PasteFENFromClipboard();
\r
5090 case IDM_MailMove:
\r
5094 case IDM_ReloadCMailMsg:
\r
5095 Reset(TRUE, TRUE);
\r
5096 ReloadCmailMsgEvent(FALSE);
\r
5099 case IDM_Minimize:
\r
5100 ShowWindow(hwnd, SW_MINIMIZE);
\r
5107 case IDM_MachineWhite:
\r
5108 MachineWhiteEvent();
\r
5110 * refresh the tags dialog only if it's visible
\r
5112 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5114 tags = PGNTags(&gameInfo);
\r
5115 TagsPopUp(tags, CmailMsg());
\r
5120 case IDM_MachineBlack:
\r
5121 MachineBlackEvent();
\r
5123 * refresh the tags dialog only if it's visible
\r
5125 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5127 tags = PGNTags(&gameInfo);
\r
5128 TagsPopUp(tags, CmailMsg());
\r
5133 case IDM_TwoMachines:
\r
5134 TwoMachinesEvent();
\r
5136 * refresh the tags dialog only if it's visible
\r
5138 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5140 tags = PGNTags(&gameInfo);
\r
5141 TagsPopUp(tags, CmailMsg());
\r
5146 case IDM_AnalysisMode:
\r
5147 if (!first.analysisSupport) {
\r
5148 char buf[MSG_SIZ];
\r
5149 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5150 DisplayError(buf, 0);
\r
5152 if (!appData.showThinking) ToggleShowThinking();
\r
5153 AnalyzeModeEvent();
\r
5157 case IDM_AnalyzeFile:
\r
5158 if (!first.analysisSupport) {
\r
5159 char buf[MSG_SIZ];
\r
5160 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5161 DisplayError(buf, 0);
\r
5163 if (!appData.showThinking) ToggleShowThinking();
\r
5164 AnalyzeFileEvent();
\r
5165 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5166 AnalysisPeriodicEvent(1);
\r
5170 case IDM_IcsClient:
\r
5174 case IDM_EditGame:
\r
5178 case IDM_EditPosition:
\r
5179 EditPositionEvent();
\r
5182 case IDM_Training:
\r
5186 case IDM_ShowGameList:
\r
5187 ShowGameListProc();
\r
5190 case IDM_EditTags:
\r
5194 case IDM_EditComment:
\r
5195 if (commentDialogUp && editComment) {
\r
5198 EditCommentEvent();
\r
5218 case IDM_CallFlag:
\r
5238 case IDM_StopObserving:
\r
5239 StopObservingEvent();
\r
5242 case IDM_StopExamining:
\r
5243 StopExaminingEvent();
\r
5246 case IDM_TypeInMove:
\r
5247 PopUpMoveDialog('\000');
\r
5250 case IDM_Backward:
\r
5252 SetFocus(hwndMain);
\r
5257 SetFocus(hwndMain);
\r
5262 SetFocus(hwndMain);
\r
5267 SetFocus(hwndMain);
\r
5274 case IDM_TruncateGame:
\r
5275 TruncateGameEvent();
\r
5282 case IDM_RetractMove:
\r
5283 RetractMoveEvent();
\r
5286 case IDM_FlipView:
\r
5287 flipView = !flipView;
\r
5288 DrawPosition(FALSE, NULL);
\r
5291 case IDM_GeneralOptions:
\r
5292 GeneralOptionsPopup(hwnd);
\r
5293 DrawPosition(TRUE, NULL);
\r
5296 case IDM_BoardOptions:
\r
5297 BoardOptionsPopup(hwnd);
\r
5300 case IDM_EnginePlayOptions:
\r
5301 EnginePlayOptionsPopup(hwnd);
\r
5304 case IDM_OptionsUCI:
\r
5305 UciOptionsPopup(hwnd);
\r
5308 case IDM_IcsOptions:
\r
5309 IcsOptionsPopup(hwnd);
\r
5313 FontsOptionsPopup(hwnd);
\r
5317 SoundOptionsPopup(hwnd);
\r
5320 case IDM_CommPort:
\r
5321 CommPortOptionsPopup(hwnd);
\r
5324 case IDM_LoadOptions:
\r
5325 LoadOptionsPopup(hwnd);
\r
5328 case IDM_SaveOptions:
\r
5329 SaveOptionsPopup(hwnd);
\r
5332 case IDM_TimeControl:
\r
5333 TimeControlOptionsPopup(hwnd);
\r
5336 case IDM_SaveSettings:
\r
5337 SaveSettings(settingsFileName);
\r
5340 case IDM_SaveSettingsOnExit:
\r
5341 saveSettingsOnExit = !saveSettingsOnExit;
\r
5342 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5343 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5344 MF_CHECKED : MF_UNCHECKED));
\r
5355 case IDM_AboutGame:
\r
5360 appData.debugMode = !appData.debugMode;
\r
5361 if (appData.debugMode) {
\r
5362 char dir[MSG_SIZ];
\r
5363 GetCurrentDirectory(MSG_SIZ, dir);
\r
5364 SetCurrentDirectory(installDir);
\r
5365 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5366 SetCurrentDirectory(dir);
\r
5367 setbuf(debugFP, NULL);
\r
5374 case IDM_HELPCONTENTS:
\r
5375 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5376 MessageBox (GetFocus(),
\r
5377 "Unable to activate help",
\r
5378 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5382 case IDM_HELPSEARCH:
\r
5383 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5384 MessageBox (GetFocus(),
\r
5385 "Unable to activate help",
\r
5386 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5390 case IDM_HELPHELP:
\r
5391 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5392 MessageBox (GetFocus(),
\r
5393 "Unable to activate help",
\r
5394 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5399 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5401 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5402 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5403 FreeProcInstance(lpProc);
\r
5406 case IDM_DirectCommand1:
\r
5407 AskQuestionEvent("Direct Command",
\r
5408 "Send to chess program:", "", "1");
\r
5410 case IDM_DirectCommand2:
\r
5411 AskQuestionEvent("Direct Command",
\r
5412 "Send to second chess program:", "", "2");
\r
5415 case EP_WhitePawn:
\r
5416 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5417 fromX = fromY = -1;
\r
5420 case EP_WhiteKnight:
\r
5421 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5422 fromX = fromY = -1;
\r
5425 case EP_WhiteBishop:
\r
5426 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5427 fromX = fromY = -1;
\r
5430 case EP_WhiteRook:
\r
5431 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5432 fromX = fromY = -1;
\r
5435 case EP_WhiteQueen:
\r
5436 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5437 fromX = fromY = -1;
\r
5440 case EP_WhiteKing:
\r
5441 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5442 fromX = fromY = -1;
\r
5445 case EP_BlackPawn:
\r
5446 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5447 fromX = fromY = -1;
\r
5450 case EP_BlackKnight:
\r
5451 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5452 fromX = fromY = -1;
\r
5455 case EP_BlackBishop:
\r
5456 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5457 fromX = fromY = -1;
\r
5460 case EP_BlackRook:
\r
5461 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5462 fromX = fromY = -1;
\r
5465 case EP_BlackQueen:
\r
5466 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5467 fromX = fromY = -1;
\r
5470 case EP_BlackKing:
\r
5471 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5472 fromX = fromY = -1;
\r
5475 case EP_EmptySquare:
\r
5476 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5477 fromX = fromY = -1;
\r
5480 case EP_ClearBoard:
\r
5481 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5482 fromX = fromY = -1;
\r
5486 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5487 fromX = fromY = -1;
\r
5491 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5492 fromX = fromY = -1;
\r
5496 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5497 fromX = fromY = -1;
\r
5501 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5502 fromX = fromY = -1;
\r
5506 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5507 fromX = fromY = -1;
\r
5511 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5512 fromX = fromY = -1;
\r
5516 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5521 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5527 case CLOCK_TIMER_ID:
\r
5528 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5529 clockTimerEvent = 0;
\r
5530 DecrementClocks(); /* call into back end */
\r
5532 case LOAD_GAME_TIMER_ID:
\r
5533 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5534 loadGameTimerEvent = 0;
\r
5535 AutoPlayGameLoop(); /* call into back end */
\r
5537 case ANALYSIS_TIMER_ID:
\r
5538 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5539 appData.periodicUpdates) {
\r
5540 AnalysisPeriodicEvent(0);
\r
5542 KillTimer(hwnd, analysisTimerEvent);
\r
5543 analysisTimerEvent = 0;
\r
5546 case DELAYED_TIMER_ID:
\r
5547 KillTimer(hwnd, delayedTimerEvent);
\r
5548 delayedTimerEvent = 0;
\r
5549 delayedTimerCallback();
\r
5554 case WM_USER_Input:
\r
5555 InputEvent(hwnd, message, wParam, lParam);
\r
5558 /* [AS] Also move "attached" child windows */
\r
5559 case WM_WINDOWPOSCHANGING:
\r
5560 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5561 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5563 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5564 /* Window is moving */
\r
5567 GetWindowRect( hwnd, &rcMain );
\r
5569 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5570 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5571 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5576 /* [AS] Snapping */
\r
5577 case WM_ENTERSIZEMOVE:
\r
5578 if (hwnd == hwndMain) {
\r
5579 doingSizing = TRUE;
\r
5582 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5586 if (hwnd == hwndMain) {
\r
5587 lastSizing = wParam;
\r
5592 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5594 case WM_EXITSIZEMOVE:
\r
5595 if (hwnd == hwndMain) {
\r
5597 doingSizing = FALSE;
\r
5598 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5599 GetClientRect(hwnd, &client);
\r
5600 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5603 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5606 case WM_DESTROY: /* message: window being destroyed */
\r
5607 PostQuitMessage(0);
\r
5611 if (hwnd == hwndMain) {
\r
5616 default: /* Passes it on if unprocessed */
\r
5617 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5622 /*---------------------------------------------------------------------------*\
\r
5624 * Misc utility routines
\r
5626 \*---------------------------------------------------------------------------*/
\r
5629 * Decent random number generator, at least not as bad as Windows
\r
5630 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5632 unsigned int randstate;
\r
5637 randstate = randstate * 1664525 + 1013904223;
\r
5638 return (int) randstate & 0x7fffffff;
\r
5642 mysrandom(unsigned int seed)
\r
5649 * returns TRUE if user selects a different color, FALSE otherwise
\r
5653 ChangeColor(HWND hwnd, COLORREF *which)
\r
5655 static BOOL firstTime = TRUE;
\r
5656 static DWORD customColors[16];
\r
5658 COLORREF newcolor;
\r
5663 /* Make initial colors in use available as custom colors */
\r
5664 /* Should we put the compiled-in defaults here instead? */
\r
5666 customColors[i++] = lightSquareColor & 0xffffff;
\r
5667 customColors[i++] = darkSquareColor & 0xffffff;
\r
5668 customColors[i++] = whitePieceColor & 0xffffff;
\r
5669 customColors[i++] = blackPieceColor & 0xffffff;
\r
5670 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5671 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5673 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5674 customColors[i++] = textAttribs[ccl].color;
\r
5676 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5677 firstTime = FALSE;
\r
5680 cc.lStructSize = sizeof(cc);
\r
5681 cc.hwndOwner = hwnd;
\r
5682 cc.hInstance = NULL;
\r
5683 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5684 cc.lpCustColors = (LPDWORD) customColors;
\r
5685 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5687 if (!ChooseColor(&cc)) return FALSE;
\r
5689 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5690 if (newcolor == *which) return FALSE;
\r
5691 *which = newcolor;
\r
5695 InitDrawingColors();
\r
5696 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5701 MyLoadSound(MySound *ms)
\r
5707 if (ms->data) free(ms->data);
\r
5710 switch (ms->name[0]) {
\r
5716 /* System sound from Control Panel. Don't preload here. */
\r
5720 if (ms->name[1] == NULLCHAR) {
\r
5721 /* "!" alone = silence */
\r
5724 /* Builtin wave resource. Error if not found. */
\r
5725 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5726 if (h == NULL) break;
\r
5727 ms->data = (void *)LoadResource(hInst, h);
\r
5728 if (h == NULL) break;
\r
5733 /* .wav file. Error if not found. */
\r
5734 f = fopen(ms->name, "rb");
\r
5735 if (f == NULL) break;
\r
5736 if (fstat(fileno(f), &st) < 0) break;
\r
5737 ms->data = malloc(st.st_size);
\r
5738 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5744 char buf[MSG_SIZ];
\r
5745 sprintf(buf, "Error loading sound %s", ms->name);
\r
5746 DisplayError(buf, GetLastError());
\r
5752 MyPlaySound(MySound *ms)
\r
5754 BOOLEAN ok = FALSE;
\r
5755 switch (ms->name[0]) {
\r
5761 /* System sound from Control Panel (deprecated feature).
\r
5762 "$" alone or an unset sound name gets default beep (still in use). */
\r
5763 if (ms->name[1]) {
\r
5764 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5766 if (!ok) ok = MessageBeep(MB_OK);
\r
5769 /* Builtin wave resource, or "!" alone for silence */
\r
5770 if (ms->name[1]) {
\r
5771 if (ms->data == NULL) return FALSE;
\r
5772 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5778 /* .wav file. Error if not found. */
\r
5779 if (ms->data == NULL) return FALSE;
\r
5780 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5783 /* Don't print an error: this can happen innocently if the sound driver
\r
5784 is busy; for instance, if another instance of WinBoard is playing
\r
5785 a sound at about the same time. */
\r
5788 char buf[MSG_SIZ];
\r
5789 sprintf(buf, "Error playing sound %s", ms->name);
\r
5790 DisplayError(buf, GetLastError());
\r
5798 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5801 OPENFILENAME *ofn;
\r
5802 static UINT *number; /* gross that this is static */
\r
5804 switch (message) {
\r
5805 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5806 /* Center the dialog over the application window */
\r
5807 ofn = (OPENFILENAME *) lParam;
\r
5808 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5809 number = (UINT *) ofn->lCustData;
\r
5810 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5814 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5815 return FALSE; /* Allow for further processing */
\r
5818 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5819 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5821 return FALSE; /* Allow for further processing */
\r
5827 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5829 static UINT *number;
\r
5830 OPENFILENAME *ofname;
\r
5833 case WM_INITDIALOG:
\r
5834 ofname = (OPENFILENAME *)lParam;
\r
5835 number = (UINT *)(ofname->lCustData);
\r
5838 ofnot = (OFNOTIFY *)lParam;
\r
5839 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5840 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5849 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5850 char *nameFilt, char *dlgTitle, UINT *number,
\r
5851 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5853 OPENFILENAME openFileName;
\r
5854 char buf1[MSG_SIZ];
\r
5857 if (fileName == NULL) fileName = buf1;
\r
5858 if (defName == NULL) {
\r
5859 strcpy(fileName, "*.");
\r
5860 strcat(fileName, defExt);
\r
5862 strcpy(fileName, defName);
\r
5864 if (fileTitle) strcpy(fileTitle, "");
\r
5865 if (number) *number = 0;
\r
5867 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5868 openFileName.hwndOwner = hwnd;
\r
5869 openFileName.hInstance = (HANDLE) hInst;
\r
5870 openFileName.lpstrFilter = nameFilt;
\r
5871 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5872 openFileName.nMaxCustFilter = 0L;
\r
5873 openFileName.nFilterIndex = 1L;
\r
5874 openFileName.lpstrFile = fileName;
\r
5875 openFileName.nMaxFile = MSG_SIZ;
\r
5876 openFileName.lpstrFileTitle = fileTitle;
\r
5877 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5878 openFileName.lpstrInitialDir = NULL;
\r
5879 openFileName.lpstrTitle = dlgTitle;
\r
5880 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5881 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5882 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5883 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5884 openFileName.nFileOffset = 0;
\r
5885 openFileName.nFileExtension = 0;
\r
5886 openFileName.lpstrDefExt = defExt;
\r
5887 openFileName.lCustData = (LONG) number;
\r
5888 openFileName.lpfnHook = oldDialog ?
\r
5889 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5890 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
5892 if (write ? GetSaveFileName(&openFileName) :
\r
5893 GetOpenFileName(&openFileName)) {
\r
5894 /* open the file */
\r
5895 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
5897 MessageBox(hwnd, "File open failed", NULL,
\r
5898 MB_OK|MB_ICONEXCLAMATION);
\r
5902 int err = CommDlgExtendedError();
\r
5903 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
5912 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
5914 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
5917 * Get the first pop-up menu in the menu template. This is the
\r
5918 * menu that TrackPopupMenu displays.
\r
5920 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
5922 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
5925 * TrackPopup uses screen coordinates, so convert the
\r
5926 * coordinates of the mouse click to screen coordinates.
\r
5928 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
5930 /* Draw and track the floating pop-up menu. */
\r
5931 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
5932 pt.x, pt.y, 0, hwnd, NULL);
\r
5934 /* Destroy the menu.*/
\r
5935 DestroyMenu(hmenu);
\r
5940 int sizeX, sizeY, newSizeX, newSizeY;
\r
5942 } ResizeEditPlusButtonsClosure;
\r
5945 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
5947 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
5951 if (hChild == cl->hText) return TRUE;
\r
5952 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
5953 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
5954 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
5955 ScreenToClient(cl->hDlg, &pt);
\r
5956 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
5957 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
5961 /* Resize a dialog that has a (rich) edit field filling most of
\r
5962 the top, with a row of buttons below */
\r
5964 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
5967 int newTextHeight, newTextWidth;
\r
5968 ResizeEditPlusButtonsClosure cl;
\r
5970 /*if (IsIconic(hDlg)) return;*/
\r
5971 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
5973 cl.hdwp = BeginDeferWindowPos(8);
\r
5975 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
5976 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
5977 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
5978 if (newTextHeight < 0) {
\r
5979 newSizeY += -newTextHeight;
\r
5980 newTextHeight = 0;
\r
5982 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
5983 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
5989 cl.newSizeX = newSizeX;
\r
5990 cl.newSizeY = newSizeY;
\r
5991 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
5993 EndDeferWindowPos(cl.hdwp);
\r
5996 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
5998 RECT rChild, rParent;
\r
5999 int wChild, hChild, wParent, hParent;
\r
6000 int wScreen, hScreen, xNew, yNew;
\r
6003 /* Get the Height and Width of the child window */
\r
6004 GetWindowRect (hwndChild, &rChild);
\r
6005 wChild = rChild.right - rChild.left;
\r
6006 hChild = rChild.bottom - rChild.top;
\r
6008 /* Get the Height and Width of the parent window */
\r
6009 GetWindowRect (hwndParent, &rParent);
\r
6010 wParent = rParent.right - rParent.left;
\r
6011 hParent = rParent.bottom - rParent.top;
\r
6013 /* Get the display limits */
\r
6014 hdc = GetDC (hwndChild);
\r
6015 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6016 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6017 ReleaseDC(hwndChild, hdc);
\r
6019 /* Calculate new X position, then adjust for screen */
\r
6020 xNew = rParent.left + ((wParent - wChild) /2);
\r
6023 } else if ((xNew+wChild) > wScreen) {
\r
6024 xNew = wScreen - wChild;
\r
6027 /* Calculate new Y position, then adjust for screen */
\r
6029 yNew = rParent.top + ((hParent - hChild) /2);
\r
6032 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6037 } else if ((yNew+hChild) > hScreen) {
\r
6038 yNew = hScreen - hChild;
\r
6041 /* Set it, and return */
\r
6042 return SetWindowPos (hwndChild, NULL,
\r
6043 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6046 /* Center one window over another */
\r
6047 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6049 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6052 /*---------------------------------------------------------------------------*\
\r
6054 * Startup Dialog functions
\r
6056 \*---------------------------------------------------------------------------*/
\r
6058 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6060 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6062 while (*cd != NULL) {
\r
6063 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6069 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6071 char buf1[ARG_MAX];
\r
6074 if (str[0] == '@') {
\r
6075 FILE* f = fopen(str + 1, "r");
\r
6077 DisplayFatalError(str + 1, errno, 2);
\r
6080 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6082 buf1[len] = NULLCHAR;
\r
6086 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6089 char buf[MSG_SIZ];
\r
6090 char *end = strchr(str, '\n');
\r
6091 if (end == NULL) return;
\r
6092 memcpy(buf, str, end - str);
\r
6093 buf[end - str] = NULLCHAR;
\r
6094 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6100 SetStartupDialogEnables(HWND hDlg)
\r
6102 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6103 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6104 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6105 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6106 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6107 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6108 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6109 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6110 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6111 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6112 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6113 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6114 IsDlgButtonChecked(hDlg, OPT_View));
\r
6118 QuoteForFilename(char *filename)
\r
6120 int dquote, space;
\r
6121 dquote = strchr(filename, '"') != NULL;
\r
6122 space = strchr(filename, ' ') != NULL;
\r
6123 if (dquote || space) {
\r
6135 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6137 char buf[MSG_SIZ];
\r
6140 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6141 q = QuoteForFilename(nthcp);
\r
6142 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6143 if (*nthdir != NULLCHAR) {
\r
6144 q = QuoteForFilename(nthdir);
\r
6145 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6147 if (*nthcp == NULLCHAR) {
\r
6148 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6149 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6150 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6151 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6156 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6158 char buf[MSG_SIZ];
\r
6162 switch (message) {
\r
6163 case WM_INITDIALOG:
\r
6164 /* Center the dialog */
\r
6165 CenterWindow (hDlg, GetDesktopWindow());
\r
6166 /* Initialize the dialog items */
\r
6167 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6168 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6169 firstChessProgramNames);
\r
6170 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6171 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6172 secondChessProgramNames);
\r
6173 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6174 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6175 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6176 if (*appData.icsHelper != NULLCHAR) {
\r
6177 char *q = QuoteForFilename(appData.icsHelper);
\r
6178 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6180 if (*appData.icsHost == NULLCHAR) {
\r
6181 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6182 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6183 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6184 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6185 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6188 if (appData.icsActive) {
\r
6189 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6191 else if (appData.noChessProgram) {
\r
6192 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6195 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6198 SetStartupDialogEnables(hDlg);
\r
6202 switch (LOWORD(wParam)) {
\r
6204 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6205 strcpy(buf, "/fcp=");
\r
6206 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6208 ParseArgs(StringGet, &p);
\r
6209 strcpy(buf, "/scp=");
\r
6210 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6212 ParseArgs(StringGet, &p);
\r
6213 appData.noChessProgram = FALSE;
\r
6214 appData.icsActive = FALSE;
\r
6215 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6216 strcpy(buf, "/ics /icshost=");
\r
6217 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6219 ParseArgs(StringGet, &p);
\r
6220 if (appData.zippyPlay) {
\r
6221 strcpy(buf, "/fcp=");
\r
6222 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6224 ParseArgs(StringGet, &p);
\r
6226 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6227 appData.noChessProgram = TRUE;
\r
6228 appData.icsActive = FALSE;
\r
6230 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6231 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6234 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6235 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6237 ParseArgs(StringGet, &p);
\r
6239 EndDialog(hDlg, TRUE);
\r
6246 case IDM_HELPCONTENTS:
\r
6247 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6248 MessageBox (GetFocus(),
\r
6249 "Unable to activate help",
\r
6250 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6255 SetStartupDialogEnables(hDlg);
\r
6263 /*---------------------------------------------------------------------------*\
\r
6265 * About box dialog functions
\r
6267 \*---------------------------------------------------------------------------*/
\r
6269 /* Process messages for "About" dialog box */
\r
6271 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6273 switch (message) {
\r
6274 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6275 /* Center the dialog over the application window */
\r
6276 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6277 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6280 case WM_COMMAND: /* message: received a command */
\r
6281 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6282 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6283 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6291 /*---------------------------------------------------------------------------*\
\r
6293 * Comment Dialog functions
\r
6295 \*---------------------------------------------------------------------------*/
\r
6298 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6300 static HANDLE hwndText = NULL;
\r
6301 int len, newSizeX, newSizeY, flags;
\r
6302 static int sizeX, sizeY;
\r
6307 switch (message) {
\r
6308 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6309 /* Initialize the dialog items */
\r
6310 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6311 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6312 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6313 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6314 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6315 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6316 SetWindowText(hDlg, commentTitle);
\r
6317 if (editComment) {
\r
6318 SetFocus(hwndText);
\r
6320 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6322 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6323 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6324 MAKELPARAM(FALSE, 0));
\r
6325 /* Size and position the dialog */
\r
6326 if (!commentDialog) {
\r
6327 commentDialog = hDlg;
\r
6328 flags = SWP_NOZORDER;
\r
6329 GetClientRect(hDlg, &rect);
\r
6330 sizeX = rect.right;
\r
6331 sizeY = rect.bottom;
\r
6332 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6333 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6334 WINDOWPLACEMENT wp;
\r
6335 EnsureOnScreen(&commentX, &commentY);
\r
6336 wp.length = sizeof(WINDOWPLACEMENT);
\r
6338 wp.showCmd = SW_SHOW;
\r
6339 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6340 wp.rcNormalPosition.left = commentX;
\r
6341 wp.rcNormalPosition.right = commentX + commentW;
\r
6342 wp.rcNormalPosition.top = commentY;
\r
6343 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6344 SetWindowPlacement(hDlg, &wp);
\r
6346 GetClientRect(hDlg, &rect);
\r
6347 newSizeX = rect.right;
\r
6348 newSizeY = rect.bottom;
\r
6349 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6350 newSizeX, newSizeY);
\r
6357 case WM_COMMAND: /* message: received a command */
\r
6358 switch (LOWORD(wParam)) {
\r
6360 if (editComment) {
\r
6362 /* Read changed options from the dialog box */
\r
6363 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6364 len = GetWindowTextLength(hwndText);
\r
6365 str = (char *) malloc(len + 1);
\r
6366 GetWindowText(hwndText, str, len + 1);
\r
6375 ReplaceComment(commentIndex, str);
\r
6382 case OPT_CancelComment:
\r
6386 case OPT_ClearComment:
\r
6387 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6390 case OPT_EditComment:
\r
6391 EditCommentEvent();
\r
6400 newSizeX = LOWORD(lParam);
\r
6401 newSizeY = HIWORD(lParam);
\r
6402 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6407 case WM_GETMINMAXINFO:
\r
6408 /* Prevent resizing window too small */
\r
6409 mmi = (MINMAXINFO *) lParam;
\r
6410 mmi->ptMinTrackSize.x = 100;
\r
6411 mmi->ptMinTrackSize.y = 100;
\r
6418 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6423 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6425 if (str == NULL) str = "";
\r
6426 p = (char *) malloc(2 * strlen(str) + 2);
\r
6429 if (*str == '\n') *q++ = '\r';
\r
6433 if (commentText != NULL) free(commentText);
\r
6435 commentIndex = index;
\r
6436 commentTitle = title;
\r
6438 editComment = edit;
\r
6440 if (commentDialog) {
\r
6441 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6442 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6444 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6445 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6446 hwndMain, (DLGPROC)lpProc);
\r
6447 FreeProcInstance(lpProc);
\r
6449 commentDialogUp = TRUE;
\r
6453 /*---------------------------------------------------------------------------*\
\r
6455 * Type-in move dialog functions
\r
6457 \*---------------------------------------------------------------------------*/
\r
6460 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6462 char move[MSG_SIZ];
\r
6464 ChessMove moveType;
\r
6465 int fromX, fromY, toX, toY;
\r
6468 switch (message) {
\r
6469 case WM_INITDIALOG:
\r
6470 move[0] = (char) lParam;
\r
6471 move[1] = NULLCHAR;
\r
6472 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6473 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6474 SetWindowText(hInput, move);
\r
6476 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6480 switch (LOWORD(wParam)) {
\r
6482 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6483 gameMode != Training) {
\r
6484 DisplayMoveError("Displayed move is not current");
\r
6486 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6487 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6488 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6489 if (gameMode != Training)
\r
6490 forwardMostMove = currentMove;
\r
6491 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6493 DisplayMoveError("Could not parse move");
\r
6496 EndDialog(hDlg, TRUE);
\r
6499 EndDialog(hDlg, FALSE);
\r
6510 PopUpMoveDialog(char firstchar)
\r
6514 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6515 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6516 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6517 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6518 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6519 gameMode == Training) {
\r
6520 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6521 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6522 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6523 FreeProcInstance(lpProc);
\r
6527 /*---------------------------------------------------------------------------*\
\r
6531 \*---------------------------------------------------------------------------*/
\r
6533 /* Nonmodal error box */
\r
6534 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6535 WPARAM wParam, LPARAM lParam);
\r
6538 ErrorPopUp(char *title, char *content)
\r
6542 BOOLEAN modal = hwndMain == NULL;
\r
6560 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6561 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6564 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6566 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6567 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6568 hwndMain, (DLGPROC)lpProc);
\r
6569 FreeProcInstance(lpProc);
\r
6576 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6577 if (errorDialog == NULL) return;
\r
6578 DestroyWindow(errorDialog);
\r
6579 errorDialog = NULL;
\r
6583 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6588 switch (message) {
\r
6589 case WM_INITDIALOG:
\r
6590 GetWindowRect(hDlg, &rChild);
\r
6593 SetWindowPos(hDlg, NULL, rChild.left,
\r
6594 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6595 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6599 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6600 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6601 and it doesn't work when you resize the dialog.
\r
6602 For now, just give it a default position.
\r
6604 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6606 errorDialog = hDlg;
\r
6607 SetWindowText(hDlg, errorTitle);
\r
6608 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6609 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6613 switch (LOWORD(wParam)) {
\r
6616 if (errorDialog == hDlg) errorDialog = NULL;
\r
6617 DestroyWindow(hDlg);
\r
6630 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6634 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6636 switch (message) {
\r
6637 case WM_INITDIALOG:
\r
6638 GetWindowRect(hDlg, &rChild);
\r
6640 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6644 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6645 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6646 and it doesn't work when you resize the dialog.
\r
6647 For now, just give it a default position.
\r
6650 SetWindowText(hDlg, errorTitle);
\r
6651 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6652 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6656 switch (LOWORD(wParam)) {
\r
6659 if (errorDialog == hDlg) errorDialog = NULL;
\r
6660 DestroyWindow(hDlg);
\r
6672 GothicPopUp(char *title)
\r
6676 BOOLEAN modal = hwndMain == NULL;
\r
6678 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6679 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6681 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6682 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6683 hwndMain, (DLGPROC)lpProc);
\r
6684 FreeProcInstance(lpProc);
\r
6688 /*---------------------------------------------------------------------------*\
\r
6690 * Ics Interaction console functions
\r
6692 \*---------------------------------------------------------------------------*/
\r
6694 #define HISTORY_SIZE 64
\r
6695 static char *history[HISTORY_SIZE];
\r
6696 int histIn = 0, histP = 0;
\r
6699 SaveInHistory(char *cmd)
\r
6701 if (history[histIn] != NULL) {
\r
6702 free(history[histIn]);
\r
6703 history[histIn] = NULL;
\r
6705 if (*cmd == NULLCHAR) return;
\r
6706 history[histIn] = StrSave(cmd);
\r
6707 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6708 if (history[histIn] != NULL) {
\r
6709 free(history[histIn]);
\r
6710 history[histIn] = NULL;
\r
6716 PrevInHistory(char *cmd)
\r
6719 if (histP == histIn) {
\r
6720 if (history[histIn] != NULL) free(history[histIn]);
\r
6721 history[histIn] = StrSave(cmd);
\r
6723 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6724 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6726 return history[histP];
\r
6732 if (histP == histIn) return NULL;
\r
6733 histP = (histP + 1) % HISTORY_SIZE;
\r
6734 return history[histP];
\r
6741 BOOLEAN immediate;
\r
6742 } IcsTextMenuEntry;
\r
6743 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6744 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6747 ParseIcsTextMenu(char *icsTextMenuString)
\r
6750 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6751 char *p = icsTextMenuString;
\r
6752 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6755 if (e->command != NULL) {
\r
6757 e->command = NULL;
\r
6761 e = icsTextMenuEntry;
\r
6762 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6763 if (*p == ';' || *p == '\n') {
\r
6764 e->item = strdup("-");
\r
6765 e->command = NULL;
\r
6767 } else if (*p == '-') {
\r
6768 e->item = strdup("-");
\r
6769 e->command = NULL;
\r
6773 char *q, *r, *s, *t;
\r
6775 q = strchr(p, ',');
\r
6776 if (q == NULL) break;
\r
6778 r = strchr(q + 1, ',');
\r
6779 if (r == NULL) break;
\r
6781 s = strchr(r + 1, ',');
\r
6782 if (s == NULL) break;
\r
6785 t = strchr(s + 1, c);
\r
6788 t = strchr(s + 1, c);
\r
6790 if (t != NULL) *t = NULLCHAR;
\r
6791 e->item = strdup(p);
\r
6792 e->command = strdup(q + 1);
\r
6793 e->getname = *(r + 1) != '0';
\r
6794 e->immediate = *(s + 1) != '0';
\r
6798 if (t == NULL) break;
\r
6807 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6811 hmenu = LoadMenu(hInst, "TextMenu");
\r
6812 h = GetSubMenu(hmenu, 0);
\r
6814 if (strcmp(e->item, "-") == 0) {
\r
6815 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6817 if (e->item[0] == '|') {
\r
6818 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6819 IDM_CommandX + i, &e->item[1]);
\r
6821 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6830 WNDPROC consoleTextWindowProc;
\r
6833 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6835 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6836 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6840 SetWindowText(hInput, command);
\r
6842 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6844 sel.cpMin = 999999;
\r
6845 sel.cpMax = 999999;
\r
6846 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6851 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6852 if (sel.cpMin == sel.cpMax) {
\r
6853 /* Expand to surrounding word */
\r
6856 tr.chrg.cpMax = sel.cpMin;
\r
6857 tr.chrg.cpMin = --sel.cpMin;
\r
6858 if (sel.cpMin < 0) break;
\r
6859 tr.lpstrText = name;
\r
6860 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6861 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6865 tr.chrg.cpMin = sel.cpMax;
\r
6866 tr.chrg.cpMax = ++sel.cpMax;
\r
6867 tr.lpstrText = name;
\r
6868 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6869 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6872 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6873 MessageBeep(MB_ICONEXCLAMATION);
\r
6877 tr.lpstrText = name;
\r
6878 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6880 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6881 MessageBeep(MB_ICONEXCLAMATION);
\r
6884 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
6887 sprintf(buf, "%s %s", command, name);
\r
6888 SetWindowText(hInput, buf);
\r
6889 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6891 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
6892 SetWindowText(hInput, buf);
\r
6893 sel.cpMin = 999999;
\r
6894 sel.cpMax = 999999;
\r
6895 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6901 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
6906 switch (message) {
\r
6908 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
6911 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
6914 sel.cpMin = 999999;
\r
6915 sel.cpMax = 999999;
\r
6916 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6917 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
6922 if (wParam == '\t') {
\r
6923 if (GetKeyState(VK_SHIFT) < 0) {
\r
6925 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
6926 if (buttonDesc[0].hwnd) {
\r
6927 SetFocus(buttonDesc[0].hwnd);
\r
6929 SetFocus(hwndMain);
\r
6933 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
6936 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6938 SendMessage(hInput, message, wParam, lParam);
\r
6942 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6944 return SendMessage(hInput, message, wParam, lParam);
\r
6945 case WM_MBUTTONDOWN:
\r
6946 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6947 case WM_RBUTTONDOWN:
\r
6948 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
6949 /* Move selection here if it was empty */
\r
6951 pt.x = LOWORD(lParam);
\r
6952 pt.y = HIWORD(lParam);
\r
6953 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6954 if (sel.cpMin == sel.cpMax) {
\r
6955 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
6956 sel.cpMax = sel.cpMin;
\r
6957 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6959 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
6962 case WM_RBUTTONUP:
\r
6963 if (GetKeyState(VK_SHIFT) & ~1) {
\r
6964 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
6965 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
6968 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
6969 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6970 if (sel.cpMin == sel.cpMax) {
\r
6971 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
6972 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
6974 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
6975 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
6977 pt.x = LOWORD(lParam);
\r
6978 pt.y = HIWORD(lParam);
\r
6979 MenuPopup(hwnd, pt, hmenu, -1);
\r
6983 switch (LOWORD(wParam)) {
\r
6984 case IDM_QuickPaste:
\r
6986 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6987 if (sel.cpMin == sel.cpMax) {
\r
6988 MessageBeep(MB_ICONEXCLAMATION);
\r
6991 SendMessage(hwnd, WM_COPY, 0, 0);
\r
6992 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6993 SendMessage(hInput, WM_PASTE, 0, 0);
\r
6998 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7001 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7004 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7008 int i = LOWORD(wParam) - IDM_CommandX;
\r
7009 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7010 icsTextMenuEntry[i].command != NULL) {
\r
7011 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7012 icsTextMenuEntry[i].getname,
\r
7013 icsTextMenuEntry[i].immediate);
\r
7021 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7024 WNDPROC consoleInputWindowProc;
\r
7027 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7029 char buf[MSG_SIZ];
\r
7031 static BOOL sendNextChar = FALSE;
\r
7032 static BOOL quoteNextChar = FALSE;
\r
7033 InputSource *is = consoleInputSource;
\r
7037 switch (message) {
\r
7039 if (!appData.localLineEditing || sendNextChar) {
\r
7040 is->buf[0] = (CHAR) wParam;
\r
7042 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7043 sendNextChar = FALSE;
\r
7046 if (quoteNextChar) {
\r
7047 buf[0] = (char) wParam;
\r
7048 buf[1] = NULLCHAR;
\r
7049 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7050 quoteNextChar = FALSE;
\r
7054 case '\r': /* Enter key */
\r
7055 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7056 if (consoleEcho) SaveInHistory(is->buf);
\r
7057 is->buf[is->count++] = '\n';
\r
7058 is->buf[is->count] = NULLCHAR;
\r
7059 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7060 if (consoleEcho) {
\r
7061 ConsoleOutput(is->buf, is->count, TRUE);
\r
7062 } else if (appData.localLineEditing) {
\r
7063 ConsoleOutput("\n", 1, TRUE);
\r
7066 case '\033': /* Escape key */
\r
7067 SetWindowText(hwnd, "");
\r
7068 cf.cbSize = sizeof(CHARFORMAT);
\r
7069 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7070 if (consoleEcho) {
\r
7071 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7073 cf.crTextColor = COLOR_ECHOOFF;
\r
7075 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7076 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7078 case '\t': /* Tab key */
\r
7079 if (GetKeyState(VK_SHIFT) < 0) {
\r
7081 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7084 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7085 if (buttonDesc[0].hwnd) {
\r
7086 SetFocus(buttonDesc[0].hwnd);
\r
7088 SetFocus(hwndMain);
\r
7092 case '\023': /* Ctrl+S */
\r
7093 sendNextChar = TRUE;
\r
7095 case '\021': /* Ctrl+Q */
\r
7096 quoteNextChar = TRUE;
\r
7105 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7106 p = PrevInHistory(buf);
\r
7108 SetWindowText(hwnd, p);
\r
7109 sel.cpMin = 999999;
\r
7110 sel.cpMax = 999999;
\r
7111 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7116 p = NextInHistory();
\r
7118 SetWindowText(hwnd, p);
\r
7119 sel.cpMin = 999999;
\r
7120 sel.cpMax = 999999;
\r
7121 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7127 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7131 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7135 case WM_MBUTTONDOWN:
\r
7136 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7137 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7139 case WM_RBUTTONUP:
\r
7140 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7141 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7142 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7146 hmenu = LoadMenu(hInst, "InputMenu");
\r
7147 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7148 if (sel.cpMin == sel.cpMax) {
\r
7149 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7150 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7152 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7153 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7155 pt.x = LOWORD(lParam);
\r
7156 pt.y = HIWORD(lParam);
\r
7157 MenuPopup(hwnd, pt, hmenu, -1);
\r
7161 switch (LOWORD(wParam)) {
\r
7163 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7165 case IDM_SelectAll:
\r
7167 sel.cpMax = -1; /*999999?*/
\r
7168 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7171 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7174 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7177 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7182 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7185 #define CO_MAX 100000
\r
7186 #define CO_TRIM 1000
\r
7189 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7191 static SnapData sd;
\r
7192 static HWND hText, hInput, hFocus;
\r
7193 InputSource *is = consoleInputSource;
\r
7195 static int sizeX, sizeY;
\r
7196 int newSizeX, newSizeY;
\r
7199 switch (message) {
\r
7200 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7201 hwndConsole = hDlg;
\r
7202 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7203 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7205 consoleTextWindowProc = (WNDPROC)
\r
7206 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7207 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7208 consoleInputWindowProc = (WNDPROC)
\r
7209 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7210 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7211 Colorize(ColorNormal, TRUE);
\r
7212 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7213 ChangedConsoleFont();
\r
7214 GetClientRect(hDlg, &rect);
\r
7215 sizeX = rect.right;
\r
7216 sizeY = rect.bottom;
\r
7217 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7218 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7219 WINDOWPLACEMENT wp;
\r
7220 EnsureOnScreen(&consoleX, &consoleY);
\r
7221 wp.length = sizeof(WINDOWPLACEMENT);
\r
7223 wp.showCmd = SW_SHOW;
\r
7224 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7225 wp.rcNormalPosition.left = consoleX;
\r
7226 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7227 wp.rcNormalPosition.top = consoleY;
\r
7228 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7229 SetWindowPlacement(hDlg, &wp);
\r
7243 if (IsIconic(hDlg)) break;
\r
7244 newSizeX = LOWORD(lParam);
\r
7245 newSizeY = HIWORD(lParam);
\r
7246 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7247 RECT rectText, rectInput;
\r
7249 int newTextHeight, newTextWidth;
\r
7250 GetWindowRect(hText, &rectText);
\r
7251 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7252 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7253 if (newTextHeight < 0) {
\r
7254 newSizeY += -newTextHeight;
\r
7255 newTextHeight = 0;
\r
7257 SetWindowPos(hText, NULL, 0, 0,
\r
7258 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7259 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7260 pt.x = rectInput.left;
\r
7261 pt.y = rectInput.top + newSizeY - sizeY;
\r
7262 ScreenToClient(hDlg, &pt);
\r
7263 SetWindowPos(hInput, NULL,
\r
7264 pt.x, pt.y, /* needs client coords */
\r
7265 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7266 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7272 case WM_GETMINMAXINFO:
\r
7273 /* Prevent resizing window too small */
\r
7274 mmi = (MINMAXINFO *) lParam;
\r
7275 mmi->ptMinTrackSize.x = 100;
\r
7276 mmi->ptMinTrackSize.y = 100;
\r
7279 /* [AS] Snapping */
\r
7280 case WM_ENTERSIZEMOVE:
\r
7281 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7284 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7287 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7289 case WM_EXITSIZEMOVE:
\r
7290 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7293 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7301 if (hwndConsole) return;
\r
7302 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7303 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7308 ConsoleOutput(char* data, int length, int forceVisible)
\r
7313 char buf[CO_MAX+1];
\r
7316 static int delayLF = 0;
\r
7317 CHARRANGE savesel, sel;
\r
7319 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7327 while (length--) {
\r
7335 } else if (*p == '\007') {
\r
7336 MyPlaySound(&sounds[(int)SoundBell]);
\r
7343 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7344 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7345 /* Save current selection */
\r
7346 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7347 exlen = GetWindowTextLength(hText);
\r
7348 /* Find out whether current end of text is visible */
\r
7349 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7350 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7351 /* Trim existing text if it's too long */
\r
7352 if (exlen + (q - buf) > CO_MAX) {
\r
7353 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7356 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7357 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7359 savesel.cpMin -= trim;
\r
7360 savesel.cpMax -= trim;
\r
7361 if (exlen < 0) exlen = 0;
\r
7362 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7363 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7365 /* Append the new text */
\r
7366 sel.cpMin = exlen;
\r
7367 sel.cpMax = exlen;
\r
7368 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7369 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7370 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7371 if (forceVisible || exlen == 0 ||
\r
7372 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7373 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7374 /* Scroll to make new end of text visible if old end of text
\r
7375 was visible or new text is an echo of user typein */
\r
7376 sel.cpMin = 9999999;
\r
7377 sel.cpMax = 9999999;
\r
7378 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7379 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7380 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7381 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7383 if (savesel.cpMax == exlen || forceVisible) {
\r
7384 /* Move insert point to new end of text if it was at the old
\r
7385 end of text or if the new text is an echo of user typein */
\r
7386 sel.cpMin = 9999999;
\r
7387 sel.cpMax = 9999999;
\r
7388 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7390 /* Restore previous selection */
\r
7391 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7393 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7400 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7404 COLORREF oldFg, oldBg;
\r
7408 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7410 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7411 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7412 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7415 rect.right = x + squareSize;
\r
7417 rect.bottom = y + squareSize;
\r
7420 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7421 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7422 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7423 &rect, str, strlen(str), NULL);
\r
7425 (void) SetTextColor(hdc, oldFg);
\r
7426 (void) SetBkColor(hdc, oldBg);
\r
7427 (void) SelectObject(hdc, oldFont);
\r
7431 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7432 RECT *rect, char *color, char *flagFell)
\r
7436 COLORREF oldFg, oldBg;
\r
7439 if (appData.clockMode) {
\r
7441 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7443 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7450 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7451 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7453 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7454 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7456 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7458 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7459 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7460 rect, str, strlen(str), NULL);
\r
7462 (void) SetTextColor(hdc, oldFg);
\r
7463 (void) SetBkColor(hdc, oldBg);
\r
7464 (void) SelectObject(hdc, oldFont);
\r
7469 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7475 if( count <= 0 ) {
\r
7476 if (appData.debugMode) {
\r
7477 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7480 return ERROR_INVALID_USER_BUFFER;
\r
7483 ResetEvent(ovl->hEvent);
\r
7484 ovl->Offset = ovl->OffsetHigh = 0;
\r
7485 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7489 err = GetLastError();
\r
7490 if (err == ERROR_IO_PENDING) {
\r
7491 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7495 err = GetLastError();
\r
7502 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7507 ResetEvent(ovl->hEvent);
\r
7508 ovl->Offset = ovl->OffsetHigh = 0;
\r
7509 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7513 err = GetLastError();
\r
7514 if (err == ERROR_IO_PENDING) {
\r
7515 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7519 err = GetLastError();
\r
7525 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7526 void CheckForInputBufferFull( InputSource * is )
\r
7528 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7529 /* Look for end of line */
\r
7530 char * p = is->buf;
\r
7532 while( p < is->next && *p != '\n' ) {
\r
7536 if( p >= is->next ) {
\r
7537 if (appData.debugMode) {
\r
7538 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7541 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7542 is->count = (DWORD) -1;
\r
7543 is->next = is->buf;
\r
7549 InputThread(LPVOID arg)
\r
7554 is = (InputSource *) arg;
\r
7555 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7556 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7557 while (is->hThread != NULL) {
\r
7558 is->error = DoReadFile(is->hFile, is->next,
\r
7559 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7560 &is->count, &ovl);
\r
7561 if (is->error == NO_ERROR) {
\r
7562 is->next += is->count;
\r
7564 if (is->error == ERROR_BROKEN_PIPE) {
\r
7565 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7568 is->count = (DWORD) -1;
\r
7569 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7574 CheckForInputBufferFull( is );
\r
7576 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7578 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7580 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7583 CloseHandle(ovl.hEvent);
\r
7584 CloseHandle(is->hFile);
\r
7586 if (appData.debugMode) {
\r
7587 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7594 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7596 NonOvlInputThread(LPVOID arg)
\r
7603 is = (InputSource *) arg;
\r
7604 while (is->hThread != NULL) {
\r
7605 is->error = ReadFile(is->hFile, is->next,
\r
7606 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7607 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7608 if (is->error == NO_ERROR) {
\r
7609 /* Change CRLF to LF */
\r
7610 if (is->next > is->buf) {
\r
7612 i = is->count + 1;
\r
7620 if (prev == '\r' && *p == '\n') {
\r
7632 if (is->error == ERROR_BROKEN_PIPE) {
\r
7633 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7636 is->count = (DWORD) -1;
\r
7640 CheckForInputBufferFull( is );
\r
7642 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7644 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7646 if (is->count < 0) break; /* Quit on error */
\r
7648 CloseHandle(is->hFile);
\r
7653 SocketInputThread(LPVOID arg)
\r
7657 is = (InputSource *) arg;
\r
7658 while (is->hThread != NULL) {
\r
7659 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7660 if ((int)is->count == SOCKET_ERROR) {
\r
7661 is->count = (DWORD) -1;
\r
7662 is->error = WSAGetLastError();
\r
7664 is->error = NO_ERROR;
\r
7665 is->next += is->count;
\r
7666 if (is->count == 0 && is->second == is) {
\r
7667 /* End of file on stderr; quit with no message */
\r
7671 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7673 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7675 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7681 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7685 is = (InputSource *) lParam;
\r
7686 if (is->lineByLine) {
\r
7687 /* Feed in lines one by one */
\r
7688 char *p = is->buf;
\r
7690 while (q < is->next) {
\r
7691 if (*q++ == '\n') {
\r
7692 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7697 /* Move any partial line to the start of the buffer */
\r
7699 while (p < is->next) {
\r
7704 if (is->error != NO_ERROR || is->count == 0) {
\r
7705 /* Notify backend of the error. Note: If there was a partial
\r
7706 line at the end, it is not flushed through. */
\r
7707 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7710 /* Feed in the whole chunk of input at once */
\r
7711 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7712 is->next = is->buf;
\r
7716 /*---------------------------------------------------------------------------*\
\r
7718 * Menu enables. Used when setting various modes.
\r
7720 \*---------------------------------------------------------------------------*/
\r
7728 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7730 while (enab->item > 0) {
\r
7731 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7736 Enables gnuEnables[] = {
\r
7737 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7738 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7739 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7740 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7741 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7742 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7743 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7744 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7745 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7746 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7750 Enables icsEnables[] = {
\r
7751 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7752 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7753 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7754 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7755 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7756 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7757 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7758 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7759 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7760 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7761 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7762 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7767 Enables zippyEnables[] = {
\r
7768 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7769 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7770 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7775 Enables ncpEnables[] = {
\r
7776 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7777 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7778 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7779 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7780 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7781 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7782 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7783 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7784 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7785 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7786 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7787 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7788 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7789 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7790 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7794 Enables trainingOnEnables[] = {
\r
7795 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7796 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7797 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7798 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7799 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7800 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7801 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7802 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7806 Enables trainingOffEnables[] = {
\r
7807 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7808 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7809 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7810 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7811 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7812 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7813 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7814 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7818 /* These modify either ncpEnables or gnuEnables */
\r
7819 Enables cmailEnables[] = {
\r
7820 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7821 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7822 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7823 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7824 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7825 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7826 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7830 Enables machineThinkingEnables[] = {
\r
7831 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7832 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7833 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7834 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7835 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7836 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7837 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7838 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7839 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7840 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7841 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7842 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7843 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7844 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7845 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7849 Enables userThinkingEnables[] = {
\r
7850 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7851 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7852 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7853 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7854 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7855 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7856 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7857 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7858 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7859 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7860 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7861 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7862 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7863 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7864 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7868 /*---------------------------------------------------------------------------*\
\r
7870 * Front-end interface functions exported by XBoard.
\r
7871 * Functions appear in same order as prototypes in frontend.h.
\r
7873 \*---------------------------------------------------------------------------*/
\r
7877 static UINT prevChecked = 0;
\r
7878 static int prevPausing = 0;
\r
7881 if (pausing != prevPausing) {
\r
7882 prevPausing = pausing;
\r
7883 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7884 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
7885 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
7888 switch (gameMode) {
\r
7889 case BeginningOfGame:
\r
7890 if (appData.icsActive)
\r
7891 nowChecked = IDM_IcsClient;
\r
7892 else if (appData.noChessProgram)
\r
7893 nowChecked = IDM_EditGame;
\r
7895 nowChecked = IDM_MachineBlack;
\r
7897 case MachinePlaysBlack:
\r
7898 nowChecked = IDM_MachineBlack;
\r
7900 case MachinePlaysWhite:
\r
7901 nowChecked = IDM_MachineWhite;
\r
7903 case TwoMachinesPlay:
\r
7904 nowChecked = IDM_TwoMachines;
\r
7907 nowChecked = IDM_AnalysisMode;
\r
7910 nowChecked = IDM_AnalyzeFile;
\r
7913 nowChecked = IDM_EditGame;
\r
7915 case PlayFromGameFile:
\r
7916 nowChecked = IDM_LoadGame;
\r
7918 case EditPosition:
\r
7919 nowChecked = IDM_EditPosition;
\r
7922 nowChecked = IDM_Training;
\r
7924 case IcsPlayingWhite:
\r
7925 case IcsPlayingBlack:
\r
7926 case IcsObserving:
\r
7928 nowChecked = IDM_IcsClient;
\r
7935 if (prevChecked != 0)
\r
7936 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7937 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
7938 if (nowChecked != 0)
\r
7939 (void) CheckMenuItem(GetMenu(hwndMain),
\r
7940 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
7942 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
7943 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
7944 MF_BYCOMMAND|MF_ENABLED);
\r
7946 (void) EnableMenuItem(GetMenu(hwndMain),
\r
7947 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
7950 prevChecked = nowChecked;
\r
7956 HMENU hmenu = GetMenu(hwndMain);
\r
7957 SetMenuEnables(hmenu, icsEnables);
\r
7958 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
7959 MF_BYPOSITION|MF_ENABLED);
\r
7961 if (appData.zippyPlay) {
\r
7962 SetMenuEnables(hmenu, zippyEnables);
\r
7970 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
7976 HMENU hmenu = GetMenu(hwndMain);
\r
7977 SetMenuEnables(hmenu, ncpEnables);
\r
7978 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
7979 MF_BYPOSITION|MF_GRAYED);
\r
7980 DrawMenuBar(hwndMain);
\r
7986 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
7990 SetTrainingModeOn()
\r
7993 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
7994 for (i = 0; i < N_BUTTONS; i++) {
\r
7995 if (buttonDesc[i].hwnd != NULL)
\r
7996 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8001 VOID SetTrainingModeOff()
\r
8004 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8005 for (i = 0; i < N_BUTTONS; i++) {
\r
8006 if (buttonDesc[i].hwnd != NULL)
\r
8007 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8013 SetUserThinkingEnables()
\r
8015 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8019 SetMachineThinkingEnables()
\r
8021 HMENU hMenu = GetMenu(hwndMain);
\r
8022 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8024 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8026 if (gameMode == MachinePlaysBlack) {
\r
8027 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8028 } else if (gameMode == MachinePlaysWhite) {
\r
8029 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8030 } else if (gameMode == TwoMachinesPlay) {
\r
8031 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8037 DisplayTitle(char *str)
\r
8039 char title[MSG_SIZ], *host;
\r
8040 if (str[0] != NULLCHAR) {
\r
8041 strcpy(title, str);
\r
8042 } else if (appData.icsActive) {
\r
8043 if (appData.icsCommPort[0] != NULLCHAR)
\r
8046 host = appData.icsHost;
\r
8047 sprintf(title, "%s: %s", szTitle, host);
\r
8048 } else if (appData.noChessProgram) {
\r
8049 strcpy(title, szTitle);
\r
8051 strcpy(title, szTitle);
\r
8052 strcat(title, ": ");
\r
8053 strcat(title, first.tidy);
\r
8055 SetWindowText(hwndMain, title);
\r
8060 DisplayMessage(char *str1, char *str2)
\r
8064 int remain = MESSAGE_TEXT_MAX - 1;
\r
8067 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8068 messageText[0] = NULLCHAR;
\r
8070 len = strlen(str1);
\r
8071 if (len > remain) len = remain;
\r
8072 strncpy(messageText, str1, len);
\r
8073 messageText[len] = NULLCHAR;
\r
8076 if (*str2 && remain >= 2) {
\r
8078 strcat(messageText, " ");
\r
8081 len = strlen(str2);
\r
8082 if (len > remain) len = remain;
\r
8083 strncat(messageText, str2, len);
\r
8085 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8087 if (IsIconic(hwndMain)) return;
\r
8088 hdc = GetDC(hwndMain);
\r
8089 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8090 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8091 &messageRect, messageText, strlen(messageText), NULL);
\r
8092 (void) SelectObject(hdc, oldFont);
\r
8093 (void) ReleaseDC(hwndMain, hdc);
\r
8097 DisplayError(char *str, int error)
\r
8099 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8105 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8106 NULL, error, LANG_NEUTRAL,
\r
8107 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8109 sprintf(buf, "%s:\n%s", str, buf2);
\r
8111 ErrorMap *em = errmap;
\r
8112 while (em->err != 0 && em->err != error) em++;
\r
8113 if (em->err != 0) {
\r
8114 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8116 sprintf(buf, "%s:\nError code %d", str, error);
\r
8121 ErrorPopUp("Error", buf);
\r
8126 DisplayMoveError(char *str)
\r
8128 fromX = fromY = -1;
\r
8129 ClearHighlights();
\r
8130 DrawPosition(FALSE, NULL);
\r
8131 if (appData.popupMoveErrors) {
\r
8132 ErrorPopUp("Error", str);
\r
8134 DisplayMessage(str, "");
\r
8135 moveErrorMessageUp = TRUE;
\r
8140 DisplayFatalError(char *str, int error, int exitStatus)
\r
8142 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8144 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8147 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8148 NULL, error, LANG_NEUTRAL,
\r
8149 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8151 sprintf(buf, "%s:\n%s", str, buf2);
\r
8153 ErrorMap *em = errmap;
\r
8154 while (em->err != 0 && em->err != error) em++;
\r
8155 if (em->err != 0) {
\r
8156 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8158 sprintf(buf, "%s:\nError code %d", str, error);
\r
8163 if (appData.debugMode) {
\r
8164 fprintf(debugFP, "%s: %s\n", label, str);
\r
8166 if (appData.popupExitMessage) {
\r
8167 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8168 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8170 ExitEvent(exitStatus);
\r
8175 DisplayInformation(char *str)
\r
8177 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8182 DisplayNote(char *str)
\r
8184 ErrorPopUp("Note", str);
\r
8189 char *title, *question, *replyPrefix;
\r
8194 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8196 static QuestionParams *qp;
\r
8197 char reply[MSG_SIZ];
\r
8200 switch (message) {
\r
8201 case WM_INITDIALOG:
\r
8202 qp = (QuestionParams *) lParam;
\r
8203 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8204 SetWindowText(hDlg, qp->title);
\r
8205 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8206 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8210 switch (LOWORD(wParam)) {
\r
8212 strcpy(reply, qp->replyPrefix);
\r
8213 if (*reply) strcat(reply, " ");
\r
8214 len = strlen(reply);
\r
8215 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8216 strcat(reply, "\n");
\r
8217 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8218 EndDialog(hDlg, TRUE);
\r
8219 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8222 EndDialog(hDlg, FALSE);
\r
8233 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8235 QuestionParams qp;
\r
8239 qp.question = question;
\r
8240 qp.replyPrefix = replyPrefix;
\r
8242 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8243 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8244 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8245 FreeProcInstance(lpProc);
\r
8248 /* [AS] Pick FRC position */
\r
8249 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8251 static int * lpIndexFRC;
\r
8257 case WM_INITDIALOG:
\r
8258 lpIndexFRC = (int *) lParam;
\r
8260 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8262 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8263 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8264 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8265 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8270 switch( LOWORD(wParam) ) {
\r
8272 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8273 EndDialog( hDlg, 0 );
\r
8276 EndDialog( hDlg, 1 );
\r
8278 case IDC_NFG_Edit:
\r
8279 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8280 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8282 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8285 case IDC_NFG_Random:
\r
8286 sprintf( buf, "%d", myrandom() % 960 );
\r
8287 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8300 int index = appData.defaultFrcPosition;
\r
8301 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8303 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8305 if( result == 0 ) {
\r
8306 appData.defaultFrcPosition = index;
\r
8312 /* [AS] Game list options */
\r
8318 static GLT_Item GLT_ItemInfo[] = {
\r
8319 { GLT_EVENT, "Event" },
\r
8320 { GLT_SITE, "Site" },
\r
8321 { GLT_DATE, "Date" },
\r
8322 { GLT_ROUND, "Round" },
\r
8323 { GLT_PLAYERS, "Players" },
\r
8324 { GLT_RESULT, "Result" },
\r
8325 { GLT_WHITE_ELO, "White Rating" },
\r
8326 { GLT_BLACK_ELO, "Black Rating" },
\r
8327 { GLT_TIME_CONTROL,"Time Control" },
\r
8328 { GLT_VARIANT, "Variant" },
\r
8329 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8333 const char * GLT_FindItem( char id )
\r
8335 const char * result = 0;
\r
8337 GLT_Item * list = GLT_ItemInfo;
\r
8339 while( list->id != 0 ) {
\r
8340 if( list->id == id ) {
\r
8341 result = list->name;
\r
8351 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8353 const char * name = GLT_FindItem( id );
\r
8356 if( index >= 0 ) {
\r
8357 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8360 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8365 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8369 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8372 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8376 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8378 pc = GLT_ALL_TAGS;
\r
8381 if( strchr( tags, *pc ) == 0 ) {
\r
8382 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8387 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8390 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8392 char result = '\0';
\r
8395 GLT_Item * list = GLT_ItemInfo;
\r
8397 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8398 while( list->id != 0 ) {
\r
8399 if( strcmp( list->name, name ) == 0 ) {
\r
8400 result = list->id;
\r
8411 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8413 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8414 int idx2 = idx1 + delta;
\r
8415 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8417 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8420 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8421 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8422 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8423 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8427 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8429 static char glt[64];
\r
8430 static char * lpUserGLT;
\r
8434 case WM_INITDIALOG:
\r
8435 lpUserGLT = (char *) lParam;
\r
8437 strcpy( glt, lpUserGLT );
\r
8439 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8441 /* Initialize list */
\r
8442 GLT_TagsToList( hDlg, glt );
\r
8444 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8449 switch( LOWORD(wParam) ) {
\r
8452 char * pc = lpUserGLT;
\r
8454 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8458 id = GLT_ListItemToTag( hDlg, idx );
\r
8462 } while( id != '\0' );
\r
8464 EndDialog( hDlg, 0 );
\r
8467 EndDialog( hDlg, 1 );
\r
8470 case IDC_GLT_Default:
\r
8471 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8472 GLT_TagsToList( hDlg, glt );
\r
8475 case IDC_GLT_Restore:
\r
8476 strcpy( glt, lpUserGLT );
\r
8477 GLT_TagsToList( hDlg, glt );
\r
8481 GLT_MoveSelection( hDlg, -1 );
\r
8484 case IDC_GLT_Down:
\r
8485 GLT_MoveSelection( hDlg, +1 );
\r
8495 int GameListOptions()
\r
8499 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8501 strcpy( glt, appData.gameListTags );
\r
8503 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8505 if( result == 0 ) {
\r
8506 /* [AS] Memory leak here! */
\r
8507 appData.gameListTags = strdup( glt );
\r
8515 DisplayIcsInteractionTitle(char *str)
\r
8517 char consoleTitle[MSG_SIZ];
\r
8519 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8520 SetWindowText(hwndConsole, consoleTitle);
\r
8524 DrawPosition(int fullRedraw, Board board)
\r
8526 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8533 fromX = fromY = -1;
\r
8534 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8535 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8536 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8537 dragInfo.lastpos = dragInfo.pos;
\r
8538 dragInfo.start.x = dragInfo.start.y = -1;
\r
8539 dragInfo.from = dragInfo.start;
\r
8541 DrawPosition(TRUE, NULL);
\r
8547 CommentPopUp(char *title, char *str)
\r
8549 HWND hwnd = GetActiveWindow();
\r
8550 EitherCommentPopUp(0, title, str, FALSE);
\r
8551 SetActiveWindow(hwnd);
\r
8555 CommentPopDown(void)
\r
8557 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8558 if (commentDialog) {
\r
8559 ShowWindow(commentDialog, SW_HIDE);
\r
8561 commentDialogUp = FALSE;
\r
8565 EditCommentPopUp(int index, char *title, char *str)
\r
8567 EitherCommentPopUp(index, title, str, TRUE);
\r
8574 MyPlaySound(&sounds[(int)SoundMove]);
\r
8577 VOID PlayIcsWinSound()
\r
8579 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8582 VOID PlayIcsLossSound()
\r
8584 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8587 VOID PlayIcsDrawSound()
\r
8589 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8592 VOID PlayIcsUnfinishedSound()
\r
8594 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8600 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8608 consoleEcho = TRUE;
\r
8609 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8610 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8611 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8620 consoleEcho = FALSE;
\r
8621 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8622 /* This works OK: set text and background both to the same color */
\r
8624 cf.crTextColor = COLOR_ECHOOFF;
\r
8625 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8626 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8629 /* No Raw()...? */
\r
8631 void Colorize(ColorClass cc, int continuation)
\r
8633 currentColorClass = cc;
\r
8634 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8635 consoleCF.crTextColor = textAttribs[cc].color;
\r
8636 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8637 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8643 static char buf[MSG_SIZ];
\r
8644 DWORD bufsiz = MSG_SIZ;
\r
8646 if (!GetUserName(buf, &bufsiz)) {
\r
8647 /*DisplayError("Error getting user name", GetLastError());*/
\r
8648 strcpy(buf, "User");
\r
8656 static char buf[MSG_SIZ];
\r
8657 DWORD bufsiz = MSG_SIZ;
\r
8659 if (!GetComputerName(buf, &bufsiz)) {
\r
8660 /*DisplayError("Error getting host name", GetLastError());*/
\r
8661 strcpy(buf, "Unknown");
\r
8668 ClockTimerRunning()
\r
8670 return clockTimerEvent != 0;
\r
8676 if (clockTimerEvent == 0) return FALSE;
\r
8677 KillTimer(hwndMain, clockTimerEvent);
\r
8678 clockTimerEvent = 0;
\r
8683 StartClockTimer(long millisec)
\r
8685 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8686 (UINT) millisec, NULL);
\r
8690 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8693 hdc = GetDC(hwndMain);
\r
8694 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8696 if (!IsIconic(hwndMain)) {
\r
8697 DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White", flag);
\r
8699 if (highlight && iconCurrent == iconBlack) {
\r
8700 iconCurrent = iconWhite;
\r
8701 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8702 if (IsIconic(hwndMain)) {
\r
8703 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8706 (void) ReleaseDC(hwndMain, hdc);
\r
8708 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8712 DisplayBlackClock(long timeRemaining, int highlight)
\r
8715 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8717 hdc = GetDC(hwndMain);
\r
8718 if (!IsIconic(hwndMain)) {
\r
8719 DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black", flag);
\r
8721 if (highlight && iconCurrent == iconWhite) {
\r
8722 iconCurrent = iconBlack;
\r
8723 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8724 if (IsIconic(hwndMain)) {
\r
8725 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8728 (void) ReleaseDC(hwndMain, hdc);
\r
8730 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8735 LoadGameTimerRunning()
\r
8737 return loadGameTimerEvent != 0;
\r
8741 StopLoadGameTimer()
\r
8743 if (loadGameTimerEvent == 0) return FALSE;
\r
8744 KillTimer(hwndMain, loadGameTimerEvent);
\r
8745 loadGameTimerEvent = 0;
\r
8750 StartLoadGameTimer(long millisec)
\r
8752 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8753 (UINT) millisec, NULL);
\r
8761 char fileTitle[MSG_SIZ];
\r
8763 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8764 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8765 appData.oldSaveStyle ? "gam" : "pgn",
\r
8767 "Save Game to File", NULL, fileTitle, NULL);
\r
8769 SaveGame(f, 0, "");
\r
8776 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8778 if (delayedTimerEvent != 0) {
\r
8779 if (appData.debugMode) {
\r
8780 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8782 KillTimer(hwndMain, delayedTimerEvent);
\r
8783 delayedTimerEvent = 0;
\r
8784 delayedTimerCallback();
\r
8786 delayedTimerCallback = cb;
\r
8787 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8788 (UINT) millisec, NULL);
\r
8791 DelayedEventCallback
\r
8794 if (delayedTimerEvent) {
\r
8795 return delayedTimerCallback;
\r
8802 CancelDelayedEvent()
\r
8804 if (delayedTimerEvent) {
\r
8805 KillTimer(hwndMain, delayedTimerEvent);
\r
8806 delayedTimerEvent = 0;
\r
8810 /* Start a child process running the given program.
\r
8811 The process's standard output can be read from "from", and its
\r
8812 standard input can be written to "to".
\r
8813 Exit with fatal error if anything goes wrong.
\r
8814 Returns an opaque pointer that can be used to destroy the process
\r
8818 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8820 #define BUFSIZE 4096
\r
8822 HANDLE hChildStdinRd, hChildStdinWr,
\r
8823 hChildStdoutRd, hChildStdoutWr;
\r
8824 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8825 SECURITY_ATTRIBUTES saAttr;
\r
8827 PROCESS_INFORMATION piProcInfo;
\r
8828 STARTUPINFO siStartInfo;
\r
8830 char buf[MSG_SIZ];
\r
8833 if (appData.debugMode) {
\r
8834 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8839 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8840 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8841 saAttr.bInheritHandle = TRUE;
\r
8842 saAttr.lpSecurityDescriptor = NULL;
\r
8845 * The steps for redirecting child's STDOUT:
\r
8846 * 1. Create anonymous pipe to be STDOUT for child.
\r
8847 * 2. Create a noninheritable duplicate of read handle,
\r
8848 * and close the inheritable read handle.
\r
8851 /* Create a pipe for the child's STDOUT. */
\r
8852 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8853 return GetLastError();
\r
8856 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8857 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8858 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8859 FALSE, /* not inherited */
\r
8860 DUPLICATE_SAME_ACCESS);
\r
8862 return GetLastError();
\r
8864 CloseHandle(hChildStdoutRd);
\r
8867 * The steps for redirecting child's STDIN:
\r
8868 * 1. Create anonymous pipe to be STDIN for child.
\r
8869 * 2. Create a noninheritable duplicate of write handle,
\r
8870 * and close the inheritable write handle.
\r
8873 /* Create a pipe for the child's STDIN. */
\r
8874 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8875 return GetLastError();
\r
8878 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8879 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8880 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8881 FALSE, /* not inherited */
\r
8882 DUPLICATE_SAME_ACCESS);
\r
8884 return GetLastError();
\r
8886 CloseHandle(hChildStdinWr);
\r
8888 /* Arrange to (1) look in dir for the child .exe file, and
\r
8889 * (2) have dir be the child's working directory. Interpret
\r
8890 * dir relative to the directory WinBoard loaded from. */
\r
8891 GetCurrentDirectory(MSG_SIZ, buf);
\r
8892 SetCurrentDirectory(installDir);
\r
8893 SetCurrentDirectory(dir);
\r
8895 /* Now create the child process. */
\r
8897 siStartInfo.cb = sizeof(STARTUPINFO);
\r
8898 siStartInfo.lpReserved = NULL;
\r
8899 siStartInfo.lpDesktop = NULL;
\r
8900 siStartInfo.lpTitle = NULL;
\r
8901 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
8902 siStartInfo.cbReserved2 = 0;
\r
8903 siStartInfo.lpReserved2 = NULL;
\r
8904 siStartInfo.hStdInput = hChildStdinRd;
\r
8905 siStartInfo.hStdOutput = hChildStdoutWr;
\r
8906 siStartInfo.hStdError = hChildStdoutWr;
\r
8908 fSuccess = CreateProcess(NULL,
\r
8909 cmdLine, /* command line */
\r
8910 NULL, /* process security attributes */
\r
8911 NULL, /* primary thread security attrs */
\r
8912 TRUE, /* handles are inherited */
\r
8913 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
8914 NULL, /* use parent's environment */
\r
8916 &siStartInfo, /* STARTUPINFO pointer */
\r
8917 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
8919 err = GetLastError();
\r
8920 SetCurrentDirectory(buf); /* return to prev directory */
\r
8925 /* Close the handles we don't need in the parent */
\r
8926 CloseHandle(piProcInfo.hThread);
\r
8927 CloseHandle(hChildStdinRd);
\r
8928 CloseHandle(hChildStdoutWr);
\r
8930 /* Prepare return value */
\r
8931 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
8932 cp->kind = CPReal;
\r
8933 cp->hProcess = piProcInfo.hProcess;
\r
8934 cp->pid = piProcInfo.dwProcessId;
\r
8935 cp->hFrom = hChildStdoutRdDup;
\r
8936 cp->hTo = hChildStdinWrDup;
\r
8938 *pr = (void *) cp;
\r
8940 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
8941 2000 where engines sometimes don't see the initial command(s)
\r
8942 from WinBoard and hang. I don't understand how that can happen,
\r
8943 but the Sleep is harmless, so I've put it in. Others have also
\r
8944 reported what may be the same problem, so hopefully this will fix
\r
8945 it for them too. */
\r
8953 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
8957 cp = (ChildProc *) pr;
\r
8958 if (cp == NULL) return;
\r
8960 switch (cp->kind) {
\r
8962 /* TerminateProcess is considered harmful, so... */
\r
8963 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
8964 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
8965 /* The following doesn't work because the chess program
\r
8966 doesn't "have the same console" as WinBoard. Maybe
\r
8967 we could arrange for this even though neither WinBoard
\r
8968 nor the chess program uses a console for stdio? */
\r
8969 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
8971 /* [AS] Special termination modes for misbehaving programs... */
\r
8972 if( signal == 9 ) {
\r
8973 if ( appData.debugMode) {
\r
8974 fprintf( debugFP, "Terminating process %u\n", cp->pid );
\r
8977 TerminateProcess( cp->hProcess, 0 );
\r
8979 else if( signal == 10 ) {
\r
8980 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
8982 if( dw != WAIT_OBJECT_0 ) {
\r
8983 if ( appData.debugMode) {
\r
8984 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
\r
8987 TerminateProcess( cp->hProcess, 0 );
\r
8991 CloseHandle(cp->hProcess);
\r
8995 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
8999 closesocket(cp->sock);
\r
9004 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9005 closesocket(cp->sock);
\r
9006 closesocket(cp->sock2);
\r
9014 InterruptChildProcess(ProcRef pr)
\r
9018 cp = (ChildProc *) pr;
\r
9019 if (cp == NULL) return;
\r
9020 switch (cp->kind) {
\r
9022 /* The following doesn't work because the chess program
\r
9023 doesn't "have the same console" as WinBoard. Maybe
\r
9024 we could arrange for this even though neither WinBoard
\r
9025 nor the chess program uses a console for stdio */
\r
9026 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9031 /* Can't interrupt */
\r
9035 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9042 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9044 char cmdLine[MSG_SIZ];
\r
9046 if (port[0] == NULLCHAR) {
\r
9047 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9049 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9051 return StartChildProcess(cmdLine, "", pr);
\r
9055 /* Code to open TCP sockets */
\r
9058 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9063 struct sockaddr_in sa, mysa;
\r
9064 struct hostent FAR *hp;
\r
9065 unsigned short uport;
\r
9066 WORD wVersionRequested;
\r
9069 /* Initialize socket DLL */
\r
9070 wVersionRequested = MAKEWORD(1, 1);
\r
9071 err = WSAStartup(wVersionRequested, &wsaData);
\r
9072 if (err != 0) return err;
\r
9075 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9076 err = WSAGetLastError();
\r
9081 /* Bind local address using (mostly) don't-care values.
\r
9083 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9084 mysa.sin_family = AF_INET;
\r
9085 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9086 uport = (unsigned short) 0;
\r
9087 mysa.sin_port = htons(uport);
\r
9088 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9089 == SOCKET_ERROR) {
\r
9090 err = WSAGetLastError();
\r
9095 /* Resolve remote host name */
\r
9096 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9097 if (!(hp = gethostbyname(host))) {
\r
9098 unsigned int b0, b1, b2, b3;
\r
9100 err = WSAGetLastError();
\r
9102 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9103 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9104 hp->h_addrtype = AF_INET;
\r
9106 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9107 hp->h_addr_list[0] = (char *) malloc(4);
\r
9108 hp->h_addr_list[0][0] = (char) b0;
\r
9109 hp->h_addr_list[0][1] = (char) b1;
\r
9110 hp->h_addr_list[0][2] = (char) b2;
\r
9111 hp->h_addr_list[0][3] = (char) b3;
\r
9117 sa.sin_family = hp->h_addrtype;
\r
9118 uport = (unsigned short) atoi(port);
\r
9119 sa.sin_port = htons(uport);
\r
9120 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9122 /* Make connection */
\r
9123 if (connect(s, (struct sockaddr *) &sa,
\r
9124 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9125 err = WSAGetLastError();
\r
9130 /* Prepare return value */
\r
9131 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9132 cp->kind = CPSock;
\r
9134 *pr = (ProcRef *) cp;
\r
9140 OpenCommPort(char *name, ProcRef *pr)
\r
9145 char fullname[MSG_SIZ];
\r
9147 if (*name != '\\')
\r
9148 sprintf(fullname, "\\\\.\\%s", name);
\r
9150 strcpy(fullname, name);
\r
9152 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9153 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9154 if (h == (HANDLE) -1) {
\r
9155 return GetLastError();
\r
9159 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9161 /* Accumulate characters until a 100ms pause, then parse */
\r
9162 ct.ReadIntervalTimeout = 100;
\r
9163 ct.ReadTotalTimeoutMultiplier = 0;
\r
9164 ct.ReadTotalTimeoutConstant = 0;
\r
9165 ct.WriteTotalTimeoutMultiplier = 0;
\r
9166 ct.WriteTotalTimeoutConstant = 0;
\r
9167 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9169 /* Prepare return value */
\r
9170 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9171 cp->kind = CPComm;
\r
9174 *pr = (ProcRef *) cp;
\r
9180 OpenLoopback(ProcRef *pr)
\r
9182 DisplayFatalError("Not implemented", 0, 1);
\r
9188 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9193 struct sockaddr_in sa, mysa;
\r
9194 struct hostent FAR *hp;
\r
9195 unsigned short uport;
\r
9196 WORD wVersionRequested;
\r
9199 char stderrPortStr[MSG_SIZ];
\r
9201 /* Initialize socket DLL */
\r
9202 wVersionRequested = MAKEWORD(1, 1);
\r
9203 err = WSAStartup(wVersionRequested, &wsaData);
\r
9204 if (err != 0) return err;
\r
9206 /* Resolve remote host name */
\r
9207 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9208 if (!(hp = gethostbyname(host))) {
\r
9209 unsigned int b0, b1, b2, b3;
\r
9211 err = WSAGetLastError();
\r
9213 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9214 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9215 hp->h_addrtype = AF_INET;
\r
9217 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9218 hp->h_addr_list[0] = (char *) malloc(4);
\r
9219 hp->h_addr_list[0][0] = (char) b0;
\r
9220 hp->h_addr_list[0][1] = (char) b1;
\r
9221 hp->h_addr_list[0][2] = (char) b2;
\r
9222 hp->h_addr_list[0][3] = (char) b3;
\r
9228 sa.sin_family = hp->h_addrtype;
\r
9229 uport = (unsigned short) 514;
\r
9230 sa.sin_port = htons(uport);
\r
9231 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9233 /* Bind local socket to unused "privileged" port address
\r
9235 s = INVALID_SOCKET;
\r
9236 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9237 mysa.sin_family = AF_INET;
\r
9238 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9239 for (fromPort = 1023;; fromPort--) {
\r
9240 if (fromPort < 0) {
\r
9242 return WSAEADDRINUSE;
\r
9244 if (s == INVALID_SOCKET) {
\r
9245 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9246 err = WSAGetLastError();
\r
9251 uport = (unsigned short) fromPort;
\r
9252 mysa.sin_port = htons(uport);
\r
9253 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9254 == SOCKET_ERROR) {
\r
9255 err = WSAGetLastError();
\r
9256 if (err == WSAEADDRINUSE) continue;
\r
9260 if (connect(s, (struct sockaddr *) &sa,
\r
9261 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9262 err = WSAGetLastError();
\r
9263 if (err == WSAEADDRINUSE) {
\r
9274 /* Bind stderr local socket to unused "privileged" port address
\r
9276 s2 = INVALID_SOCKET;
\r
9277 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9278 mysa.sin_family = AF_INET;
\r
9279 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9280 for (fromPort = 1023;; fromPort--) {
\r
9281 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9282 if (fromPort < 0) {
\r
9283 (void) closesocket(s);
\r
9285 return WSAEADDRINUSE;
\r
9287 if (s2 == INVALID_SOCKET) {
\r
9288 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9289 err = WSAGetLastError();
\r
9295 uport = (unsigned short) fromPort;
\r
9296 mysa.sin_port = htons(uport);
\r
9297 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9298 == SOCKET_ERROR) {
\r
9299 err = WSAGetLastError();
\r
9300 if (err == WSAEADDRINUSE) continue;
\r
9301 (void) closesocket(s);
\r
9305 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9306 err = WSAGetLastError();
\r
9307 if (err == WSAEADDRINUSE) {
\r
9309 s2 = INVALID_SOCKET;
\r
9312 (void) closesocket(s);
\r
9313 (void) closesocket(s2);
\r
9319 prevStderrPort = fromPort; // remember port used
\r
9320 sprintf(stderrPortStr, "%d", fromPort);
\r
9322 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9323 err = WSAGetLastError();
\r
9324 (void) closesocket(s);
\r
9325 (void) closesocket(s2);
\r
9330 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9331 err = WSAGetLastError();
\r
9332 (void) closesocket(s);
\r
9333 (void) closesocket(s2);
\r
9337 if (*user == NULLCHAR) user = UserName();
\r
9338 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9339 err = WSAGetLastError();
\r
9340 (void) closesocket(s);
\r
9341 (void) closesocket(s2);
\r
9345 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9346 err = WSAGetLastError();
\r
9347 (void) closesocket(s);
\r
9348 (void) closesocket(s2);
\r
9353 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9354 err = WSAGetLastError();
\r
9355 (void) closesocket(s);
\r
9356 (void) closesocket(s2);
\r
9360 (void) closesocket(s2); /* Stop listening */
\r
9362 /* Prepare return value */
\r
9363 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9364 cp->kind = CPRcmd;
\r
9367 *pr = (ProcRef *) cp;
\r
9374 AddInputSource(ProcRef pr, int lineByLine,
\r
9375 InputCallback func, VOIDSTAR closure)
\r
9377 InputSource *is, *is2 = NULL;
\r
9378 ChildProc *cp = (ChildProc *) pr;
\r
9380 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9381 is->lineByLine = lineByLine;
\r
9383 is->closure = closure;
\r
9384 is->second = NULL;
\r
9385 is->next = is->buf;
\r
9386 if (pr == NoProc) {
\r
9387 is->kind = CPReal;
\r
9388 consoleInputSource = is;
\r
9390 is->kind = cp->kind;
\r
9392 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9393 we create all threads suspended so that the is->hThread variable can be
\r
9394 safely assigned, then let the threads start with ResumeThread.
\r
9396 switch (cp->kind) {
\r
9398 is->hFile = cp->hFrom;
\r
9399 cp->hFrom = NULL; /* now owned by InputThread */
\r
9401 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9402 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9406 is->hFile = cp->hFrom;
\r
9407 cp->hFrom = NULL; /* now owned by InputThread */
\r
9409 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9410 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9414 is->sock = cp->sock;
\r
9416 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9417 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9421 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9423 is->sock = cp->sock;
\r
9425 is2->sock = cp->sock2;
\r
9426 is2->second = is2;
\r
9428 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9429 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9431 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9432 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9436 if( is->hThread != NULL ) {
\r
9437 ResumeThread( is->hThread );
\r
9440 if( is2 != NULL && is2->hThread != NULL ) {
\r
9441 ResumeThread( is2->hThread );
\r
9445 return (InputSourceRef) is;
\r
9449 RemoveInputSource(InputSourceRef isr)
\r
9453 is = (InputSource *) isr;
\r
9454 is->hThread = NULL; /* tell thread to stop */
\r
9455 CloseHandle(is->hThread);
\r
9456 if (is->second != NULL) {
\r
9457 is->second->hThread = NULL;
\r
9458 CloseHandle(is->second->hThread);
\r
9464 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9467 int outCount = SOCKET_ERROR;
\r
9468 ChildProc *cp = (ChildProc *) pr;
\r
9469 static OVERLAPPED ovl;
\r
9471 if (pr == NoProc) {
\r
9472 ConsoleOutput(message, count, FALSE);
\r
9476 if (ovl.hEvent == NULL) {
\r
9477 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9479 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9481 switch (cp->kind) {
\r
9484 outCount = send(cp->sock, message, count, 0);
\r
9485 if (outCount == SOCKET_ERROR) {
\r
9486 *outError = WSAGetLastError();
\r
9488 *outError = NO_ERROR;
\r
9493 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9494 &dOutCount, NULL)) {
\r
9495 *outError = NO_ERROR;
\r
9496 outCount = (int) dOutCount;
\r
9498 *outError = GetLastError();
\r
9503 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9504 &dOutCount, &ovl);
\r
9505 if (*outError == NO_ERROR) {
\r
9506 outCount = (int) dOutCount;
\r
9514 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9517 /* Ignore delay, not implemented for WinBoard */
\r
9518 return OutputToProcess(pr, message, count, outError);
\r
9523 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9524 char *buf, int count, int error)
\r
9526 DisplayFatalError("Not implemented", 0, 1);
\r
9529 /* see wgamelist.c for Game List functions */
\r
9530 /* see wedittags.c for Edit Tags functions */
\r
9537 char buf[MSG_SIZ];
\r
9540 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9541 f = fopen(buf, "r");
\r
9543 ProcessICSInitScript(f);
\r
9551 StartAnalysisClock()
\r
9553 if (analysisTimerEvent) return;
\r
9554 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9555 (UINT) 2000, NULL);
\r
9559 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9561 static HANDLE hwndText;
\r
9563 static int sizeX, sizeY;
\r
9564 int newSizeX, newSizeY, flags;
\r
9567 switch (message) {
\r
9568 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9569 /* Initialize the dialog items */
\r
9570 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9571 SetWindowText(hDlg, analysisTitle);
\r
9572 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9573 /* Size and position the dialog */
\r
9574 if (!analysisDialog) {
\r
9575 analysisDialog = hDlg;
\r
9576 flags = SWP_NOZORDER;
\r
9577 GetClientRect(hDlg, &rect);
\r
9578 sizeX = rect.right;
\r
9579 sizeY = rect.bottom;
\r
9580 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9581 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9582 WINDOWPLACEMENT wp;
\r
9583 EnsureOnScreen(&analysisX, &analysisY);
\r
9584 wp.length = sizeof(WINDOWPLACEMENT);
\r
9586 wp.showCmd = SW_SHOW;
\r
9587 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9588 wp.rcNormalPosition.left = analysisX;
\r
9589 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9590 wp.rcNormalPosition.top = analysisY;
\r
9591 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9592 SetWindowPlacement(hDlg, &wp);
\r
9594 GetClientRect(hDlg, &rect);
\r
9595 newSizeX = rect.right;
\r
9596 newSizeY = rect.bottom;
\r
9597 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9598 newSizeX, newSizeY);
\r
9605 case WM_COMMAND: /* message: received a command */
\r
9606 switch (LOWORD(wParam)) {
\r
9616 newSizeX = LOWORD(lParam);
\r
9617 newSizeY = HIWORD(lParam);
\r
9618 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9623 case WM_GETMINMAXINFO:
\r
9624 /* Prevent resizing window too small */
\r
9625 mmi = (MINMAXINFO *) lParam;
\r
9626 mmi->ptMinTrackSize.x = 100;
\r
9627 mmi->ptMinTrackSize.y = 100;
\r
9634 AnalysisPopUp(char* title, char* str)
\r
9640 EngineOutputPopUp();
\r
9643 if (str == NULL) str = "";
\r
9644 p = (char *) malloc(2 * strlen(str) + 2);
\r
9647 if (*str == '\n') *q++ = '\r';
\r
9651 if (analysisText != NULL) free(analysisText);
\r
9654 if (analysisDialog) {
\r
9655 SetWindowText(analysisDialog, title);
\r
9656 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9657 ShowWindow(analysisDialog, SW_SHOW);
\r
9659 analysisTitle = title;
\r
9660 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9661 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9662 hwndMain, (DLGPROC)lpProc);
\r
9663 FreeProcInstance(lpProc);
\r
9665 analysisDialogUp = TRUE;
\r
9671 if (analysisDialog) {
\r
9672 ShowWindow(analysisDialog, SW_HIDE);
\r
9674 analysisDialogUp = FALSE;
\r
9679 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9681 highlightInfo.sq[0].x = fromX;
\r
9682 highlightInfo.sq[0].y = fromY;
\r
9683 highlightInfo.sq[1].x = toX;
\r
9684 highlightInfo.sq[1].y = toY;
\r
9690 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9691 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9695 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9697 premoveHighlightInfo.sq[0].x = fromX;
\r
9698 premoveHighlightInfo.sq[0].y = fromY;
\r
9699 premoveHighlightInfo.sq[1].x = toX;
\r
9700 premoveHighlightInfo.sq[1].y = toY;
\r
9704 ClearPremoveHighlights()
\r
9706 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9707 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9711 ShutDownFrontEnd()
\r
9713 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9714 DeleteClipboardTempFiles();
\r
9720 if (IsIconic(hwndMain))
\r
9721 ShowWindow(hwndMain, SW_RESTORE);
\r
9723 SetActiveWindow(hwndMain);
\r
9727 * Prototypes for animation support routines
\r
9729 static void ScreenSquare(int column, int row, POINT * pt);
\r
9730 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9731 POINT frames[], int * nFrames);
\r
9737 AnimateMove(board, fromX, fromY, toX, toY)
\r
9744 ChessSquare piece;
\r
9745 POINT start, finish, mid;
\r
9746 POINT frames[kFactor * 2 + 1];
\r
9749 if (!appData.animate) return;
\r
9750 if (doingSizing) return;
\r
9751 if (fromY < 0 || fromX < 0) return;
\r
9752 piece = board[fromY][fromX];
\r
9753 if (piece >= EmptySquare) return;
\r
9755 ScreenSquare(fromX, fromY, &start);
\r
9756 ScreenSquare(toX, toY, &finish);
\r
9758 /* All pieces except knights move in straight line */
\r
9759 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9760 mid.x = start.x + (finish.x - start.x) / 2;
\r
9761 mid.y = start.y + (finish.y - start.y) / 2;
\r
9763 /* Knight: make diagonal movement then straight */
\r
9764 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9765 mid.x = start.x + (finish.x - start.x) / 2;
\r
9769 mid.y = start.y + (finish.y - start.y) / 2;
\r
9773 /* Don't use as many frames for very short moves */
\r
9774 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9775 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9777 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9779 animInfo.from.x = fromX;
\r
9780 animInfo.from.y = fromY;
\r
9781 animInfo.to.x = toX;
\r
9782 animInfo.to.y = toY;
\r
9783 animInfo.lastpos = start;
\r
9784 animInfo.piece = piece;
\r
9785 for (n = 0; n < nFrames; n++) {
\r
9786 animInfo.pos = frames[n];
\r
9787 DrawPosition(FALSE, NULL);
\r
9788 animInfo.lastpos = animInfo.pos;
\r
9789 Sleep(appData.animSpeed);
\r
9791 animInfo.pos = finish;
\r
9792 DrawPosition(FALSE, NULL);
\r
9793 animInfo.piece = EmptySquare;
\r
9796 /* Convert board position to corner of screen rect and color */
\r
9799 ScreenSquare(column, row, pt)
\r
9800 int column; int row; POINT * pt;
\r
9803 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9804 pt->y = lineGap + row * (squareSize + lineGap);
\r
9806 pt->x = lineGap + column * (squareSize + lineGap);
\r
9807 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9811 /* Generate a series of frame coords from start->mid->finish.
\r
9812 The movement rate doubles until the half way point is
\r
9813 reached, then halves back down to the final destination,
\r
9814 which gives a nice slow in/out effect. The algorithmn
\r
9815 may seem to generate too many intermediates for short
\r
9816 moves, but remember that the purpose is to attract the
\r
9817 viewers attention to the piece about to be moved and
\r
9818 then to where it ends up. Too few frames would be less
\r
9822 Tween(start, mid, finish, factor, frames, nFrames)
\r
9823 POINT * start; POINT * mid;
\r
9824 POINT * finish; int factor;
\r
9825 POINT frames[]; int * nFrames;
\r
9827 int n, fraction = 1, count = 0;
\r
9829 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9830 for (n = 0; n < factor; n++)
\r
9832 for (n = 0; n < factor; n++) {
\r
9833 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9834 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9836 fraction = fraction / 2;
\r
9840 frames[count] = *mid;
\r
9843 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9845 for (n = 0; n < factor; n++) {
\r
9846 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9847 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9849 fraction = fraction * 2;
\r
9855 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9860 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
9861 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
9863 OutputDebugString( buf );
\r
9866 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9868 EvalGraphSet( first, last, current, pvInfoList );
\r
9871 void SetProgramStats( FrontEndProgramStats * stats )
\r
9876 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
9877 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
9879 OutputDebugString( buf );
\r
9882 EngineOutputUpdate( stats );
\r