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,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
65 #include <sys/stat.h>
\r
68 #include <commdlg.h>
\r
70 #include <richedit.h>
\r
71 #include <mmsystem.h>
\r
79 #include "winboard.h"
\r
80 #include "frontend.h"
\r
81 #include "backend.h"
\r
83 #include "wclipbrd.h"
\r
84 #include "wgamelist.h"
\r
85 #include "wedittags.h"
\r
86 #include "woptions.h"
\r
87 #include "wsockerr.h"
\r
88 #include "defaults.h"
\r
92 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
95 void mysrandom(unsigned int seed);
\r
97 extern int whiteFlag, blackFlag;
\r
98 Boolean flipClock = FALSE;
\r
100 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 ChessSquare piece;
\r
104 POINT pos; /* window coordinates of current pos */
\r
105 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
106 POINT from; /* board coordinates of the piece's orig pos */
\r
107 POINT to; /* board coordinates of the piece's new pos */
\r
110 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
113 POINT start; /* window coordinates of start pos */
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
119 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
122 POINT sq[2]; /* board coordinates of from, to squares */
\r
125 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
126 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
128 /* Window class names */
\r
129 char szAppName[] = "WinBoard";
\r
130 char szConsoleName[] = "WBConsole";
\r
132 /* Title bar text */
\r
133 char szTitle[] = "WinBoard";
\r
134 char szConsoleTitle[] = "ICS Interaction";
\r
137 char *settingsFileName;
\r
138 BOOLEAN saveSettingsOnExit;
\r
139 char installDir[MSG_SIZ];
\r
141 BoardSize boardSize;
\r
142 BOOLEAN chessProgram;
\r
143 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
144 static int squareSize, lineGap, minorSize;
\r
145 static int winWidth, winHeight;
\r
146 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
147 static int logoHeight = 0;
\r
148 static char messageText[MESSAGE_TEXT_MAX];
\r
149 static int clockTimerEvent = 0;
\r
150 static int loadGameTimerEvent = 0;
\r
151 static int analysisTimerEvent = 0;
\r
152 static DelayedEventCallback delayedTimerCallback;
\r
153 static int delayedTimerEvent = 0;
\r
154 static int buttonCount = 2;
\r
155 char *icsTextMenuString;
\r
157 char *firstChessProgramNames;
\r
158 char *secondChessProgramNames;
\r
160 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
162 #define PALETTESIZE 256
\r
164 HINSTANCE hInst; /* current instance */
\r
165 HWND hwndMain = NULL; /* root window*/
\r
166 HWND hwndConsole = NULL;
\r
167 BOOLEAN alwaysOnTop = FALSE;
\r
169 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
170 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
172 ColorClass currentColorClass;
\r
174 HWND hCommPort = NULL; /* currently open comm port */
\r
175 static HWND hwndPause; /* pause button */
\r
176 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
177 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
178 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
179 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
180 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
181 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
182 static HPEN gridPen = NULL;
\r
183 static HPEN highlightPen = NULL;
\r
184 static HPEN premovePen = NULL;
\r
185 static NPLOGPALETTE pLogPal;
\r
186 static BOOL paletteChanged = FALSE;
\r
187 static HICON iconWhite, iconBlack, iconCurrent;
\r
188 static int doingSizing = FALSE;
\r
189 static int lastSizing = 0;
\r
190 static int prevStderrPort;
\r
192 /* [AS] Support for background textures */
\r
193 #define BACK_TEXTURE_MODE_DISABLED 0
\r
194 #define BACK_TEXTURE_MODE_PLAIN 1
\r
195 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
197 static HBITMAP liteBackTexture = NULL;
\r
198 static HBITMAP darkBackTexture = NULL;
\r
199 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
200 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
201 static int backTextureSquareSize = 0;
\r
202 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
204 #if __GNUC__ && !defined(_winmajor)
\r
205 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
207 #define oldDialog (_winmajor < 4)
\r
210 char *defaultTextAttribs[] =
\r
212 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
213 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
223 int cliWidth, cliHeight;
\r
226 SizeInfo sizeInfo[] =
\r
228 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
229 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
230 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
231 { "petite", 33, 1, 1, 1, 0, 0 },
\r
232 { "slim", 37, 2, 1, 0, 0, 0 },
\r
233 { "small", 40, 2, 1, 0, 0, 0 },
\r
234 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
235 { "middling", 49, 2, 0, 0, 0, 0 },
\r
236 { "average", 54, 2, 0, 0, 0, 0 },
\r
237 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
238 { "medium", 64, 3, 0, 0, 0, 0 },
\r
239 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
240 { "large", 80, 3, 0, 0, 0, 0 },
\r
241 { "big", 87, 3, 0, 0, 0, 0 },
\r
242 { "huge", 95, 3, 0, 0, 0, 0 },
\r
243 { "giant", 108, 3, 0, 0, 0, 0 },
\r
244 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
245 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
246 { NULL, 0, 0, 0, 0, 0, 0 }
\r
249 #define MF(x) {x, {0, }, {0, }, 0}
\r
250 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
272 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
281 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
282 #define N_BUTTONS 5
\r
284 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
286 {"<<", IDM_ToStart, NULL, NULL},
\r
287 {"<", IDM_Backward, NULL, NULL},
\r
288 {"P", IDM_Pause, NULL, NULL},
\r
289 {">", IDM_Forward, NULL, NULL},
\r
290 {">>", IDM_ToEnd, NULL, NULL},
\r
293 int tinyLayout = 0, smallLayout = 0;
\r
294 #define MENU_BAR_ITEMS 6
\r
295 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
296 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
297 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
301 MySound sounds[(int)NSoundClasses];
\r
302 MyTextAttribs textAttribs[(int)NColorClasses];
\r
304 MyColorizeAttribs colorizeAttribs[] = {
\r
305 { (COLORREF)0, 0, "Shout Text" },
\r
306 { (COLORREF)0, 0, "SShout/CShout" },
\r
307 { (COLORREF)0, 0, "Channel 1 Text" },
\r
308 { (COLORREF)0, 0, "Channel Text" },
\r
309 { (COLORREF)0, 0, "Kibitz Text" },
\r
310 { (COLORREF)0, 0, "Tell Text" },
\r
311 { (COLORREF)0, 0, "Challenge Text" },
\r
312 { (COLORREF)0, 0, "Request Text" },
\r
313 { (COLORREF)0, 0, "Seek Text" },
\r
314 { (COLORREF)0, 0, "Normal Text" },
\r
315 { (COLORREF)0, 0, "None" }
\r
320 static char *commentTitle;
\r
321 static char *commentText;
\r
322 static int commentIndex;
\r
323 static Boolean editComment = FALSE;
\r
324 HWND commentDialog = NULL;
\r
325 BOOLEAN commentDialogUp = FALSE;
\r
326 static int commentX, commentY, commentH, commentW;
\r
328 static char *analysisTitle;
\r
329 static char *analysisText;
\r
330 HWND analysisDialog = NULL;
\r
331 BOOLEAN analysisDialogUp = FALSE;
\r
332 static int analysisX, analysisY, analysisH, analysisW;
\r
334 char errorTitle[MSG_SIZ];
\r
335 char errorMessage[2*MSG_SIZ];
\r
336 HWND errorDialog = NULL;
\r
337 BOOLEAN moveErrorMessageUp = FALSE;
\r
338 BOOLEAN consoleEcho = TRUE;
\r
339 CHARFORMAT consoleCF;
\r
340 COLORREF consoleBackgroundColor;
\r
342 char *programVersion;
\r
348 typedef int CPKind;
\r
357 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
360 #define INPUT_SOURCE_BUF_SIZE 4096
\r
362 typedef struct _InputSource {
\r
369 char buf[INPUT_SOURCE_BUF_SIZE];
\r
373 InputCallback func;
\r
374 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
378 InputSource *consoleInputSource;
\r
383 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
384 VOID ConsoleCreate();
\r
386 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
387 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
388 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
389 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
391 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
392 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
393 void ParseIcsTextMenu(char *icsTextMenuString);
\r
394 VOID PopUpMoveDialog(char firstchar);
\r
395 VOID PopUpNameDialog(char firstchar);
\r
396 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
400 int GameListOptions();
\r
402 HWND moveHistoryDialog = NULL;
\r
403 BOOLEAN moveHistoryDialogUp = FALSE;
\r
405 WindowPlacement wpMoveHistory;
\r
407 HWND evalGraphDialog = NULL;
\r
408 BOOLEAN evalGraphDialogUp = FALSE;
\r
410 WindowPlacement wpEvalGraph;
\r
412 HWND engineOutputDialog = NULL;
\r
413 BOOLEAN engineOutputDialogUp = FALSE;
\r
415 WindowPlacement wpEngineOutput;
\r
417 VOID MoveHistoryPopUp();
\r
418 VOID MoveHistoryPopDown();
\r
419 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
420 BOOL MoveHistoryIsUp();
\r
422 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
423 VOID EvalGraphPopUp();
\r
424 VOID EvalGraphPopDown();
\r
425 BOOL EvalGraphIsUp();
\r
427 VOID EngineOutputPopUp();
\r
428 VOID EngineOutputPopDown();
\r
429 BOOL EngineOutputIsUp();
\r
430 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
432 VOID GothicPopUp(char *title, VariantClass variant);
\r
434 * Setting "frozen" should disable all user input other than deleting
\r
435 * the window. We do this while engines are initializing themselves.
\r
437 static int frozen = 0;
\r
438 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
444 if (frozen) return;
\r
446 hmenu = GetMenu(hwndMain);
\r
447 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
448 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
450 DrawMenuBar(hwndMain);
\r
453 /* Undo a FreezeUI */
\r
459 if (!frozen) return;
\r
461 hmenu = GetMenu(hwndMain);
\r
462 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
463 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
465 DrawMenuBar(hwndMain);
\r
468 /*---------------------------------------------------------------------------*\
\r
472 \*---------------------------------------------------------------------------*/
\r
475 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
476 LPSTR lpCmdLine, int nCmdShow)
\r
479 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
483 LoadLibrary("RICHED32.DLL");
\r
484 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
486 if (!InitApplication(hInstance)) {
\r
489 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
493 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
494 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
495 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
497 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
499 while (GetMessage(&msg, /* message structure */
\r
500 NULL, /* handle of window receiving the message */
\r
501 0, /* lowest message to examine */
\r
502 0)) /* highest message to examine */
\r
504 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
505 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
506 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
507 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
508 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
509 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
510 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
511 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
512 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
513 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
514 TranslateMessage(&msg); /* Translates virtual key codes */
\r
515 DispatchMessage(&msg); /* Dispatches message to window */
\r
520 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
523 /*---------------------------------------------------------------------------*\
\r
525 * Initialization functions
\r
527 \*---------------------------------------------------------------------------*/
\r
530 InitApplication(HINSTANCE hInstance)
\r
534 /* Fill in window class structure with parameters that describe the */
\r
537 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
538 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
539 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
540 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
541 wc.hInstance = hInstance; /* Owner of this class */
\r
542 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
543 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
544 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
545 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
546 wc.lpszClassName = szAppName; /* Name to register as */
\r
548 /* Register the window class and return success/failure code. */
\r
549 if (!RegisterClass(&wc)) return FALSE;
\r
551 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
552 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
554 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
555 wc.hInstance = hInstance;
\r
556 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
557 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
558 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
559 wc.lpszMenuName = NULL;
\r
560 wc.lpszClassName = szConsoleName;
\r
562 if (!RegisterClass(&wc)) return FALSE;
\r
567 /* Set by InitInstance, used by EnsureOnScreen */
\r
568 int screenHeight, screenWidth;
\r
571 EnsureOnScreen(int *x, int *y)
\r
573 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
574 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
575 if (*x > screenWidth - 32) *x = 0;
\r
576 if (*y > screenHeight - 32) *y = 0;
\r
577 if (*x < 0) *x = 0;
\r
578 if (*y < 0) *y = 0;
\r
579 // if (*x < 10) *x = 10;
\r
580 // if (*y < gap) *y = gap;
\r
584 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
586 HWND hwnd; /* Main window handle. */
\r
588 WINDOWPLACEMENT wp;
\r
591 hInst = hInstance; /* Store instance handle in our global variable */
\r
593 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
594 *filepart = NULLCHAR;
\r
596 GetCurrentDirectory(MSG_SIZ, installDir);
\r
598 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
599 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
600 if (appData.debugMode) {
\r
601 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
602 setbuf(debugFP, NULL);
\r
607 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
608 // InitEngineUCI( installDir, &second );
\r
610 /* Create a main window for this application instance. */
\r
611 hwnd = CreateWindow(szAppName, szTitle,
\r
612 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
613 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
614 NULL, NULL, hInstance, NULL);
\r
617 /* If window could not be created, return "failure" */
\r
622 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
623 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
624 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
626 if (first.programLogo == NULL && appData.debugMode) {
\r
627 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
629 } else if(appData.autoLogo) {
\r
630 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
632 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
633 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
637 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
638 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
640 if (second.programLogo == NULL && appData.debugMode) {
\r
641 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
643 } else if(appData.autoLogo) {
\r
644 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
646 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
647 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
651 iconWhite = LoadIcon(hInstance, "icon_white");
\r
652 iconBlack = LoadIcon(hInstance, "icon_black");
\r
653 iconCurrent = iconWhite;
\r
654 InitDrawingColors();
\r
655 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
656 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
657 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
658 /* Compute window size for each board size, and use the largest
\r
659 size that fits on this screen as the default. */
\r
660 InitDrawingSizes((BoardSize)ibs, 0);
\r
661 if (boardSize == (BoardSize)-1 &&
\r
662 winHeight <= screenHeight
\r
663 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
664 && winWidth <= screenWidth) {
\r
665 boardSize = (BoardSize)ibs;
\r
669 InitDrawingSizes(boardSize, 0);
\r
671 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
673 /* [AS] Load textures if specified */
\r
674 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
676 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
677 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
678 liteBackTextureMode = appData.liteBackTextureMode;
\r
680 if (liteBackTexture == NULL && appData.debugMode) {
\r
681 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
685 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
686 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
687 darkBackTextureMode = appData.darkBackTextureMode;
\r
689 if (darkBackTexture == NULL && appData.debugMode) {
\r
690 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
694 mysrandom( (unsigned) time(NULL) );
\r
696 /* [AS] Restore layout */
\r
697 if( wpMoveHistory.visible ) {
\r
698 MoveHistoryPopUp();
\r
701 if( wpEvalGraph.visible ) {
\r
705 if( wpEngineOutput.visible ) {
\r
706 EngineOutputPopUp();
\r
711 /* Make the window visible; update its client area; and return "success" */
\r
712 EnsureOnScreen(&boardX, &boardY);
\r
713 wp.length = sizeof(WINDOWPLACEMENT);
\r
715 wp.showCmd = nCmdShow;
\r
716 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
717 wp.rcNormalPosition.left = boardX;
\r
718 wp.rcNormalPosition.right = boardX + winWidth;
\r
719 wp.rcNormalPosition.top = boardY;
\r
720 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
721 SetWindowPlacement(hwndMain, &wp);
\r
723 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
724 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
727 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
728 if( gameInfo.variant != VariantFischeRandom ) {
\r
729 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
734 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
735 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
737 ShowWindow(hwndConsole, nCmdShow);
\r
739 UpdateWindow(hwnd);
\r
747 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
748 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
749 ArgSettingsFilename
\r
757 String *pString; // ArgString
\r
758 int *pInt; // ArgInt
\r
759 float *pFloat; // ArgFloat
\r
760 Boolean *pBoolean; // ArgBoolean
\r
761 COLORREF *pColor; // ArgColor
\r
762 ColorClass cc; // ArgAttribs
\r
763 String *pFilename; // ArgFilename
\r
764 BoardSize *pBoardSize; // ArgBoardSize
\r
765 int whichFont; // ArgFont
\r
766 DCB *pDCB; // ArgCommSettings
\r
767 String *pFilename; // ArgSettingsFilename
\r
775 ArgDescriptor argDescriptors[] = {
\r
776 /* positional arguments */
\r
777 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
778 { "", ArgNone, NULL },
\r
779 /* keyword arguments */
\r
780 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
781 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
782 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
783 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
784 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
785 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
786 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
787 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
788 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
789 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
790 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
791 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
792 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
793 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
794 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
795 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
796 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
797 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
799 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
801 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
803 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
804 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
806 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
807 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
808 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
809 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
810 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
811 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
812 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
813 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
814 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
815 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
816 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
817 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
818 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
819 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
820 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
821 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
822 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
823 /*!!bitmapDirectory?*/
\r
824 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
825 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
826 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
827 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
828 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
829 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
830 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
831 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
832 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
833 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
834 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
835 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
836 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
837 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
838 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
839 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
840 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
841 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
842 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
843 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
844 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
845 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
846 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
847 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
848 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
849 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
850 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
851 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
852 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
853 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
854 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
855 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
856 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
857 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
858 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
859 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
860 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
861 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
862 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
863 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
864 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
865 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
866 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
867 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
868 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
869 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
870 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
871 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
872 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
873 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
874 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
875 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
876 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
877 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
878 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
879 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
880 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
881 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
882 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
883 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
884 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
885 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
886 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
887 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
888 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
889 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
890 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
891 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
892 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
893 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
894 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
895 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
896 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
897 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
898 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
899 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
900 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
901 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
902 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
903 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
904 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
905 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
906 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
907 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
908 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
909 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
910 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
911 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
912 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
913 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
914 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
915 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
916 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
917 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
918 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
919 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
920 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
921 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
922 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
923 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
924 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
925 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
926 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
927 TRUE }, /* must come after all fonts */
\r
928 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
929 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
930 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
931 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
932 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
933 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
934 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
935 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
936 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
937 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
938 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
939 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
940 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
941 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
942 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
943 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
944 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
945 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
946 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
947 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
948 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
949 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
950 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
951 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
952 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
953 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
954 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
955 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
956 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
957 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
958 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
960 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
961 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
963 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
964 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
965 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
966 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
967 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
968 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
969 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
970 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
971 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
972 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
973 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
974 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
975 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
976 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
977 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
978 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
979 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
980 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
981 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
982 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
983 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
984 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
985 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
986 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
987 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
988 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
989 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
990 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
991 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
992 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
993 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
994 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
995 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
996 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
997 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
998 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
999 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1000 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1001 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1002 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1003 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1004 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1005 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1006 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1007 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1008 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1009 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1010 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1011 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1012 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1013 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1014 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1015 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1016 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1017 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1018 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1019 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1020 { "highlightLastMove", ArgBoolean,
\r
1021 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1022 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1023 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1024 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1025 { "highlightDragging", ArgBoolean,
\r
1026 (LPVOID) &appData.highlightDragging, TRUE },
\r
1027 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1028 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1029 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1030 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1031 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1032 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1033 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1034 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1035 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1036 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1037 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1038 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1039 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1040 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1041 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1042 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1043 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1044 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1045 { "soundShout", ArgFilename,
\r
1046 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1047 { "soundSShout", ArgFilename,
\r
1048 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1049 { "soundChannel1", ArgFilename,
\r
1050 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1051 { "soundChannel", ArgFilename,
\r
1052 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1053 { "soundKibitz", ArgFilename,
\r
1054 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1055 { "soundTell", ArgFilename,
\r
1056 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1057 { "soundChallenge", ArgFilename,
\r
1058 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1059 { "soundRequest", ArgFilename,
\r
1060 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1061 { "soundSeek", ArgFilename,
\r
1062 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1063 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1064 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1065 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1066 { "soundIcsLoss", ArgFilename,
\r
1067 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1068 { "soundIcsDraw", ArgFilename,
\r
1069 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1070 { "soundIcsUnfinished", ArgFilename,
\r
1071 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1072 { "soundIcsAlarm", ArgFilename,
\r
1073 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1074 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1075 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1076 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1077 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1078 { "reuseChessPrograms", ArgBoolean,
\r
1079 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1080 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1081 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1082 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1083 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1084 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1085 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1086 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1087 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1088 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1089 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1090 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1091 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1092 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1093 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1094 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1095 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1096 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1097 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1098 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1099 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1100 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1101 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1102 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1103 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1104 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1105 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1106 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1107 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1108 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1109 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1110 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1111 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1112 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1113 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1114 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1115 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1116 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1118 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1120 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1121 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1122 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1123 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1124 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1125 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1126 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1127 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1128 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1129 /* [AS] New features */
\r
1130 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1131 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1132 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1133 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1134 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1135 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1136 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1137 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1138 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1139 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1140 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1141 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1142 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1143 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1144 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1145 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1146 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1147 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1148 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1149 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1150 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1151 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1152 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1153 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1154 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1155 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1156 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1157 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1158 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1159 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1160 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1161 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1162 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1163 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1164 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1165 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1166 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1167 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1168 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1169 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1170 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1171 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1172 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1173 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1174 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1175 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1176 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1177 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1178 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1179 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1181 /* [AS] Layout stuff */
\r
1182 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1183 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1184 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1185 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1186 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1188 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1189 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1190 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1191 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1192 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1194 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1195 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1196 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1197 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1198 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1200 /* [HGM] board-size, adjudication and misc. options */
\r
1201 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1202 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1203 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1204 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1205 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1206 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1207 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1208 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1209 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1210 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1211 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1212 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1213 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1214 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1215 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1216 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1217 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1218 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1219 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1220 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1221 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1222 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1223 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1224 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1225 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1226 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1227 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1228 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1229 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1232 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1233 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1234 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1235 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1236 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1237 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1238 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1239 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1240 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1241 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1242 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1243 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1244 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1246 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1247 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1248 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1249 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1250 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1251 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1252 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1254 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1255 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1256 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1257 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1258 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1259 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1260 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1261 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1262 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1263 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1264 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1265 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1266 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1267 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1268 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1269 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1270 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1271 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1273 /* [HGM] options for broadcasting and time odds */
\r
1274 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1275 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1276 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1277 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1278 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1279 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1280 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1281 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1282 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1283 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1284 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1285 { NULL, ArgNone, NULL, FALSE }
\r
1289 /* Kludge for indirection files on command line */
\r
1290 char* lastIndirectionFilename;
\r
1291 ArgDescriptor argDescriptorIndirection =
\r
1292 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1296 ExitArgError(char *msg, char *badArg)
\r
1298 char buf[MSG_SIZ];
\r
1300 sprintf(buf, "%s %s", msg, badArg);
\r
1301 DisplayFatalError(buf, 0, 2);
\r
1305 /* Command line font name parser. NULL name means do nothing.
\r
1306 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1307 For backward compatibility, syntax without the colon is also
\r
1308 accepted, but font names with digits in them won't work in that case.
\r
1311 ParseFontName(char *name, MyFontParams *mfp)
\r
1314 if (name == NULL) return;
\r
1316 q = strchr(p, ':');
\r
1318 if (q - p >= sizeof(mfp->faceName))
\r
1319 ExitArgError("Font name too long:", name);
\r
1320 memcpy(mfp->faceName, p, q - p);
\r
1321 mfp->faceName[q - p] = NULLCHAR;
\r
1324 q = mfp->faceName;
\r
1325 while (*p && !isdigit(*p)) {
\r
1327 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1328 ExitArgError("Font name too long:", name);
\r
1330 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1333 if (!*p) ExitArgError("Font point size missing:", name);
\r
1334 mfp->pointSize = (float) atof(p);
\r
1335 mfp->bold = (strchr(p, 'b') != NULL);
\r
1336 mfp->italic = (strchr(p, 'i') != NULL);
\r
1337 mfp->underline = (strchr(p, 'u') != NULL);
\r
1338 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1341 /* Color name parser.
\r
1342 X version accepts X color names, but this one
\r
1343 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1345 ParseColorName(char *name)
\r
1347 int red, green, blue, count;
\r
1348 char buf[MSG_SIZ];
\r
1350 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1352 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1353 &red, &green, &blue);
\r
1356 sprintf(buf, "Can't parse color name %s", name);
\r
1357 DisplayError(buf, 0);
\r
1358 return RGB(0, 0, 0);
\r
1360 return PALETTERGB(red, green, blue);
\r
1364 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1366 char *e = argValue;
\r
1370 if (*e == 'b') eff |= CFE_BOLD;
\r
1371 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1372 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1373 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1374 else if (*e == '#' || isdigit(*e)) break;
\r
1378 *color = ParseColorName(e);
\r
1383 ParseBoardSize(char *name)
\r
1385 BoardSize bs = SizeTiny;
\r
1386 while (sizeInfo[bs].name != NULL) {
\r
1387 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1390 ExitArgError("Unrecognized board size value", name);
\r
1391 return bs; /* not reached */
\r
1396 StringGet(void *getClosure)
\r
1398 char **p = (char **) getClosure;
\r
1403 FileGet(void *getClosure)
\r
1406 FILE* f = (FILE*) getClosure;
\r
1415 /* Parse settings file named "name". If file found, return the
\r
1416 full name in fullname and return TRUE; else return FALSE */
\r
1418 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1423 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1424 f = fopen(fullname, "r");
\r
1426 ParseArgs(FileGet, f);
\r
1435 ParseArgs(GetFunc get, void *cl)
\r
1437 char argName[ARG_MAX];
\r
1438 char argValue[ARG_MAX];
\r
1439 ArgDescriptor *ad;
\r
1448 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1449 if (ch == NULLCHAR) break;
\r
1451 /* Comment to end of line */
\r
1453 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1455 } else if (ch == '/' || ch == '-') {
\r
1458 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1459 ch != '\n' && ch != '\t') {
\r
1465 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1466 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1468 if (ad->argName == NULL)
\r
1469 ExitArgError("Unrecognized argument", argName);
\r
1471 } else if (ch == '@') {
\r
1472 /* Indirection file */
\r
1473 ad = &argDescriptorIndirection;
\r
1476 /* Positional argument */
\r
1477 ad = &argDescriptors[posarg++];
\r
1478 strcpy(argName, ad->argName);
\r
1481 if (ad->argType == ArgTrue) {
\r
1482 *(Boolean *) ad->argLoc = TRUE;
\r
1485 if (ad->argType == ArgFalse) {
\r
1486 *(Boolean *) ad->argLoc = FALSE;
\r
1490 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1491 if (ch == NULLCHAR || ch == '\n') {
\r
1492 ExitArgError("No value provided for argument", argName);
\r
1496 // Quoting with { }. No characters have to (or can) be escaped.
\r
1497 // Thus the string cannot contain a '}' character.
\r
1517 } else if (ch == '\'' || ch == '"') {
\r
1518 // Quoting with ' ' or " ", with \ as escape character.
\r
1519 // Inconvenient for long strings that may contain Windows filenames.
\r
1536 if (ch == start) {
\r
1545 if (ad->argType == ArgFilename
\r
1546 || ad->argType == ArgSettingsFilename) {
\r
1552 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1576 for (i = 0; i < 3; i++) {
\r
1577 if (ch >= '0' && ch <= '7') {
\r
1578 octval = octval*8 + (ch - '0');
\r
1585 *q++ = (char) octval;
\r
1596 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1603 switch (ad->argType) {
\r
1605 *(int *) ad->argLoc = atoi(argValue);
\r
1609 *(float *) ad->argLoc = (float) atof(argValue);
\r
1614 *(char **) ad->argLoc = strdup(argValue);
\r
1617 case ArgSettingsFilename:
\r
1619 char fullname[MSG_SIZ];
\r
1620 if (ParseSettingsFile(argValue, fullname)) {
\r
1621 if (ad->argLoc != NULL) {
\r
1622 *(char **) ad->argLoc = strdup(fullname);
\r
1625 if (ad->argLoc != NULL) {
\r
1627 ExitArgError("Failed to open indirection file", argValue);
\r
1634 switch (argValue[0]) {
\r
1637 *(Boolean *) ad->argLoc = TRUE;
\r
1641 *(Boolean *) ad->argLoc = FALSE;
\r
1644 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1650 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1653 case ArgAttribs: {
\r
1654 ColorClass cc = (ColorClass)ad->argLoc;
\r
1655 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1659 case ArgBoardSize:
\r
1660 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1664 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1667 case ArgCommSettings:
\r
1668 ParseCommSettings(argValue, &dcb);
\r
1672 ExitArgError("Unrecognized argument", argValue);
\r
1679 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1681 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1682 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1685 lf->lfEscapement = 0;
\r
1686 lf->lfOrientation = 0;
\r
1687 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1688 lf->lfItalic = mfp->italic;
\r
1689 lf->lfUnderline = mfp->underline;
\r
1690 lf->lfStrikeOut = mfp->strikeout;
\r
1691 lf->lfCharSet = DEFAULT_CHARSET;
\r
1692 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1693 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1694 lf->lfQuality = DEFAULT_QUALITY;
\r
1695 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1696 strcpy(lf->lfFaceName, mfp->faceName);
\r
1700 CreateFontInMF(MyFont *mf)
\r
1702 LFfromMFP(&mf->lf, &mf->mfp);
\r
1703 if (mf->hf) DeleteObject(mf->hf);
\r
1704 mf->hf = CreateFontIndirect(&mf->lf);
\r
1708 SetDefaultTextAttribs()
\r
1711 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1712 ParseAttribs(&textAttribs[cc].color,
\r
1713 &textAttribs[cc].effects,
\r
1714 defaultTextAttribs[cc]);
\r
1719 SetDefaultSounds()
\r
1723 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1724 textAttribs[cc].sound.name = strdup("");
\r
1725 textAttribs[cc].sound.data = NULL;
\r
1727 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1728 sounds[sc].name = strdup("");
\r
1729 sounds[sc].data = NULL;
\r
1731 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1739 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1740 MyLoadSound(&textAttribs[cc].sound);
\r
1742 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1743 MyLoadSound(&sounds[sc]);
\r
1748 InitAppData(LPSTR lpCmdLine)
\r
1751 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1754 programName = szAppName;
\r
1756 /* Initialize to defaults */
\r
1757 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1758 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1759 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1760 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1761 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1762 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1763 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1764 SetDefaultTextAttribs();
\r
1765 SetDefaultSounds();
\r
1766 appData.movesPerSession = MOVES_PER_SESSION;
\r
1767 appData.initString = INIT_STRING;
\r
1768 appData.secondInitString = INIT_STRING;
\r
1769 appData.firstComputerString = COMPUTER_STRING;
\r
1770 appData.secondComputerString = COMPUTER_STRING;
\r
1771 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1772 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1773 appData.firstPlaysBlack = FALSE;
\r
1774 appData.noChessProgram = FALSE;
\r
1775 chessProgram = FALSE;
\r
1776 appData.firstHost = FIRST_HOST;
\r
1777 appData.secondHost = SECOND_HOST;
\r
1778 appData.firstDirectory = FIRST_DIRECTORY;
\r
1779 appData.secondDirectory = SECOND_DIRECTORY;
\r
1780 appData.bitmapDirectory = "";
\r
1781 appData.remoteShell = REMOTE_SHELL;
\r
1782 appData.remoteUser = "";
\r
1783 appData.timeDelay = TIME_DELAY;
\r
1784 appData.timeControl = TIME_CONTROL;
\r
1785 appData.timeIncrement = TIME_INCREMENT;
\r
1786 appData.icsActive = FALSE;
\r
1787 appData.icsHost = "";
\r
1788 appData.icsPort = ICS_PORT;
\r
1789 appData.icsCommPort = ICS_COMM_PORT;
\r
1790 appData.icsLogon = ICS_LOGON;
\r
1791 appData.icsHelper = "";
\r
1792 appData.useTelnet = FALSE;
\r
1793 appData.telnetProgram = TELNET_PROGRAM;
\r
1794 appData.gateway = "";
\r
1795 appData.loadGameFile = "";
\r
1796 appData.loadGameIndex = 0;
\r
1797 appData.saveGameFile = "";
\r
1798 appData.autoSaveGames = FALSE;
\r
1799 appData.loadPositionFile = "";
\r
1800 appData.loadPositionIndex = 1;
\r
1801 appData.savePositionFile = "";
\r
1802 appData.matchMode = FALSE;
\r
1803 appData.matchGames = 0;
\r
1804 appData.monoMode = FALSE;
\r
1805 appData.debugMode = FALSE;
\r
1806 appData.clockMode = TRUE;
\r
1807 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1808 appData.Iconic = FALSE; /*unused*/
\r
1809 appData.searchTime = "";
\r
1810 appData.searchDepth = 0;
\r
1811 appData.showCoords = FALSE;
\r
1812 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1813 appData.autoCallFlag = FALSE;
\r
1814 appData.flipView = FALSE;
\r
1815 appData.autoFlipView = TRUE;
\r
1816 appData.cmailGameName = "";
\r
1817 appData.alwaysPromoteToQueen = FALSE;
\r
1818 appData.oldSaveStyle = FALSE;
\r
1819 appData.quietPlay = FALSE;
\r
1820 appData.showThinking = FALSE;
\r
1821 appData.ponderNextMove = TRUE;
\r
1822 appData.periodicUpdates = TRUE;
\r
1823 appData.popupExitMessage = TRUE;
\r
1824 appData.popupMoveErrors = FALSE;
\r
1825 appData.autoObserve = FALSE;
\r
1826 appData.autoComment = FALSE;
\r
1827 appData.animate = TRUE;
\r
1828 appData.animSpeed = 10;
\r
1829 appData.animateDragging = TRUE;
\r
1830 appData.highlightLastMove = TRUE;
\r
1831 appData.getMoveList = TRUE;
\r
1832 appData.testLegality = TRUE;
\r
1833 appData.premove = TRUE;
\r
1834 appData.premoveWhite = FALSE;
\r
1835 appData.premoveWhiteText = "";
\r
1836 appData.premoveBlack = FALSE;
\r
1837 appData.premoveBlackText = "";
\r
1838 appData.icsAlarm = TRUE;
\r
1839 appData.icsAlarmTime = 5000;
\r
1840 appData.autoRaiseBoard = TRUE;
\r
1841 appData.localLineEditing = TRUE;
\r
1842 appData.colorize = TRUE;
\r
1843 appData.reuseFirst = TRUE;
\r
1844 appData.reuseSecond = TRUE;
\r
1845 appData.blindfold = FALSE;
\r
1846 appData.icsEngineAnalyze = FALSE;
\r
1847 dcb.DCBlength = sizeof(DCB);
\r
1848 dcb.BaudRate = 9600;
\r
1849 dcb.fBinary = TRUE;
\r
1850 dcb.fParity = FALSE;
\r
1851 dcb.fOutxCtsFlow = FALSE;
\r
1852 dcb.fOutxDsrFlow = FALSE;
\r
1853 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1854 dcb.fDsrSensitivity = FALSE;
\r
1855 dcb.fTXContinueOnXoff = TRUE;
\r
1856 dcb.fOutX = FALSE;
\r
1858 dcb.fNull = FALSE;
\r
1859 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1860 dcb.fAbortOnError = FALSE;
\r
1861 /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */
\r
1862 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
\r
1863 //dcb.wReserved = 0;
\r
1865 dcb.wReserved = 0;
\r
1868 dcb.Parity = SPACEPARITY;
\r
1869 dcb.StopBits = ONESTOPBIT;
\r
1870 settingsFileName = SETTINGS_FILE;
\r
1871 saveSettingsOnExit = TRUE;
\r
1872 boardX = CW_USEDEFAULT;
\r
1873 boardY = CW_USEDEFAULT;
\r
1874 consoleX = CW_USEDEFAULT;
\r
1875 consoleY = CW_USEDEFAULT;
\r
1876 consoleW = CW_USEDEFAULT;
\r
1877 consoleH = CW_USEDEFAULT;
\r
1878 analysisX = CW_USEDEFAULT;
\r
1879 analysisY = CW_USEDEFAULT;
\r
1880 analysisW = CW_USEDEFAULT;
\r
1881 analysisH = CW_USEDEFAULT;
\r
1882 commentX = CW_USEDEFAULT;
\r
1883 commentY = CW_USEDEFAULT;
\r
1884 commentW = CW_USEDEFAULT;
\r
1885 commentH = CW_USEDEFAULT;
\r
1886 editTagsX = CW_USEDEFAULT;
\r
1887 editTagsY = CW_USEDEFAULT;
\r
1888 editTagsW = CW_USEDEFAULT;
\r
1889 editTagsH = CW_USEDEFAULT;
\r
1890 gameListX = CW_USEDEFAULT;
\r
1891 gameListY = CW_USEDEFAULT;
\r
1892 gameListW = CW_USEDEFAULT;
\r
1893 gameListH = CW_USEDEFAULT;
\r
1894 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1895 icsNames = ICS_NAMES;
\r
1896 firstChessProgramNames = FCP_NAMES;
\r
1897 secondChessProgramNames = SCP_NAMES;
\r
1898 appData.initialMode = "";
\r
1899 appData.variant = "normal";
\r
1900 appData.firstProtocolVersion = PROTOVER;
\r
1901 appData.secondProtocolVersion = PROTOVER;
\r
1902 appData.showButtonBar = TRUE;
\r
1904 /* [AS] New properties (see comments in header file) */
\r
1905 appData.firstScoreIsAbsolute = FALSE;
\r
1906 appData.secondScoreIsAbsolute = FALSE;
\r
1907 appData.saveExtendedInfoInPGN = FALSE;
\r
1908 appData.hideThinkingFromHuman = FALSE;
\r
1909 appData.liteBackTextureFile = "";
\r
1910 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1911 appData.darkBackTextureFile = "";
\r
1912 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1913 appData.renderPiecesWithFont = "";
\r
1914 appData.fontToPieceTable = "";
\r
1915 appData.fontBackColorWhite = 0;
\r
1916 appData.fontForeColorWhite = 0;
\r
1917 appData.fontBackColorBlack = 0;
\r
1918 appData.fontForeColorBlack = 0;
\r
1919 appData.fontPieceSize = 80;
\r
1920 appData.overrideLineGap = 1;
\r
1921 appData.adjudicateLossThreshold = 0;
\r
1922 appData.delayBeforeQuit = 0;
\r
1923 appData.delayAfterQuit = 0;
\r
1924 appData.nameOfDebugFile = "winboard.debug";
\r
1925 appData.pgnEventHeader = "Computer Chess Game";
\r
1926 appData.defaultFrcPosition = -1;
\r
1927 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1928 appData.saveOutOfBookInfo = TRUE;
\r
1929 appData.showEvalInMoveHistory = TRUE;
\r
1930 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1931 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1932 appData.highlightMoveWithArrow = FALSE;
\r
1933 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1934 appData.useStickyWindows = TRUE;
\r
1935 appData.adjudicateDrawMoves = 0;
\r
1936 appData.autoDisplayComment = TRUE;
\r
1937 appData.autoDisplayTags = TRUE;
\r
1938 appData.firstIsUCI = FALSE;
\r
1939 appData.secondIsUCI = FALSE;
\r
1940 appData.firstHasOwnBookUCI = TRUE;
\r
1941 appData.secondHasOwnBookUCI = TRUE;
\r
1942 appData.polyglotDir = "";
\r
1943 appData.usePolyglotBook = FALSE;
\r
1944 appData.polyglotBook = "";
\r
1945 appData.defaultHashSize = 64;
\r
1946 appData.defaultCacheSizeEGTB = 4;
\r
1947 appData.defaultPathEGTB = "c:\\egtb";
\r
1948 appData.firstOptions = "";
\r
1949 appData.secondOptions = "";
\r
1951 InitWindowPlacement( &wpMoveHistory );
\r
1952 InitWindowPlacement( &wpEvalGraph );
\r
1953 InitWindowPlacement( &wpEngineOutput );
\r
1955 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1956 appData.NrFiles = -1;
\r
1957 appData.NrRanks = -1;
\r
1958 appData.holdingsSize = -1;
\r
1959 appData.testClaims = FALSE;
\r
1960 appData.checkMates = FALSE;
\r
1961 appData.materialDraws= FALSE;
\r
1962 appData.trivialDraws = FALSE;
\r
1963 appData.ruleMoves = 51;
\r
1964 appData.drawRepeats = 6;
\r
1965 appData.matchPause = 10000;
\r
1966 appData.alphaRank = FALSE;
\r
1967 appData.allWhite = FALSE;
\r
1968 appData.upsideDown = FALSE;
\r
1969 appData.serverPause = 15;
\r
1970 appData.serverMovesName = NULL;
\r
1971 appData.suppressLoadMoves = FALSE;
\r
1972 appData.firstTimeOdds = 1;
\r
1973 appData.secondTimeOdds = 1;
\r
1974 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1975 appData.secondAccumulateTC = 1;
\r
1976 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1977 appData.secondNPS = -1;
\r
1978 appData.engineComments = 1;
\r
1979 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1980 appData.egtFormats = "";
\r
1983 appData.zippyTalk = ZIPPY_TALK;
\r
1984 appData.zippyPlay = ZIPPY_PLAY;
\r
1985 appData.zippyLines = ZIPPY_LINES;
\r
1986 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1987 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1988 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1989 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1990 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1991 appData.zippyUseI = ZIPPY_USE_I;
\r
1992 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1993 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1994 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1995 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1996 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1997 appData.zippyAbort = ZIPPY_ABORT;
\r
1998 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1999 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2000 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2003 /* Point font array elements to structures and
\r
2004 parse default font names */
\r
2005 for (i=0; i<NUM_FONTS; i++) {
\r
2006 for (j=0; j<NUM_SIZES; j++) {
\r
2007 font[j][i] = &fontRec[j][i];
\r
2008 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2012 /* Parse default settings file if any */
\r
2013 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2014 settingsFileName = strdup(buf);
\r
2017 /* Parse command line */
\r
2018 ParseArgs(StringGet, &lpCmdLine);
\r
2020 /* [HGM] make sure board size is acceptable */
\r
2021 if(appData.NrFiles > BOARD_SIZE ||
\r
2022 appData.NrRanks > BOARD_SIZE )
\r
2023 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2025 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2026 * with options from the command line, we now make an even higher priority
\r
2027 * overrule by WB options attached to the engine command line. This so that
\r
2028 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2031 if(appData.firstChessProgram != NULL) {
\r
2032 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2033 static char *f = "first";
\r
2034 char buf[MSG_SIZ], *q = buf;
\r
2035 if(p != NULL) { // engine command line contains WinBoard options
\r
2036 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2037 ParseArgs(StringGet, &q);
\r
2038 p[-1] = 0; // cut them offengine command line
\r
2041 // now do same for second chess program
\r
2042 if(appData.secondChessProgram != NULL) {
\r
2043 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2044 static char *s = "second";
\r
2045 char buf[MSG_SIZ], *q = buf;
\r
2046 if(p != NULL) { // engine command line contains WinBoard options
\r
2047 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2048 ParseArgs(StringGet, &q);
\r
2049 p[-1] = 0; // cut them offengine command line
\r
2054 /* Propagate options that affect others */
\r
2055 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2056 if (appData.icsActive || appData.noChessProgram) {
\r
2057 chessProgram = FALSE; /* not local chess program mode */
\r
2060 /* Open startup dialog if needed */
\r
2061 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2062 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2063 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2064 *appData.secondChessProgram == NULLCHAR))) {
\r
2067 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2068 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2069 FreeProcInstance(lpProc);
\r
2072 /* Make sure save files land in the right (?) directory */
\r
2073 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2074 appData.saveGameFile = strdup(buf);
\r
2076 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2077 appData.savePositionFile = strdup(buf);
\r
2080 /* Finish initialization for fonts and sounds */
\r
2081 for (i=0; i<NUM_FONTS; i++) {
\r
2082 for (j=0; j<NUM_SIZES; j++) {
\r
2083 CreateFontInMF(font[j][i]);
\r
2086 /* xboard, and older WinBoards, controlled the move sound with the
\r
2087 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2088 always turn the option on (so that the backend will call us),
\r
2089 then let the user turn the sound off by setting it to silence if
\r
2090 desired. To accommodate old winboard.ini files saved by old
\r
2091 versions of WinBoard, we also turn off the sound if the option
\r
2092 was initially set to false. */
\r
2093 if (!appData.ringBellAfterMoves) {
\r
2094 sounds[(int)SoundMove].name = strdup("");
\r
2095 appData.ringBellAfterMoves = TRUE;
\r
2097 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2098 SetCurrentDirectory(installDir);
\r
2100 SetCurrentDirectory(currDir);
\r
2102 p = icsTextMenuString;
\r
2103 if (p[0] == '@') {
\r
2104 FILE* f = fopen(p + 1, "r");
\r
2106 DisplayFatalError(p + 1, errno, 2);
\r
2109 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2111 buf[i] = NULLCHAR;
\r
2114 ParseIcsTextMenu(strdup(p));
\r
2121 HMENU hmenu = GetMenu(hwndMain);
\r
2123 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2124 MF_BYCOMMAND|((appData.icsActive &&
\r
2125 *appData.icsCommPort != NULLCHAR) ?
\r
2126 MF_ENABLED : MF_GRAYED));
\r
2127 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2128 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2129 MF_CHECKED : MF_UNCHECKED));
\r
2134 SaveSettings(char* name)
\r
2137 ArgDescriptor *ad;
\r
2138 WINDOWPLACEMENT wp;
\r
2139 char dir[MSG_SIZ];
\r
2141 if (!hwndMain) return;
\r
2143 GetCurrentDirectory(MSG_SIZ, dir);
\r
2144 SetCurrentDirectory(installDir);
\r
2145 f = fopen(name, "w");
\r
2146 SetCurrentDirectory(dir);
\r
2148 DisplayError(name, errno);
\r
2151 fprintf(f, ";\n");
\r
2152 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2153 fprintf(f, ";\n");
\r
2154 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2155 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2156 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2157 fprintf(f, ";\n");
\r
2159 wp.length = sizeof(WINDOWPLACEMENT);
\r
2160 GetWindowPlacement(hwndMain, &wp);
\r
2161 boardX = wp.rcNormalPosition.left;
\r
2162 boardY = wp.rcNormalPosition.top;
\r
2164 if (hwndConsole) {
\r
2165 GetWindowPlacement(hwndConsole, &wp);
\r
2166 consoleX = wp.rcNormalPosition.left;
\r
2167 consoleY = wp.rcNormalPosition.top;
\r
2168 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2169 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2172 if (analysisDialog) {
\r
2173 GetWindowPlacement(analysisDialog, &wp);
\r
2174 analysisX = wp.rcNormalPosition.left;
\r
2175 analysisY = wp.rcNormalPosition.top;
\r
2176 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2177 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2180 if (commentDialog) {
\r
2181 GetWindowPlacement(commentDialog, &wp);
\r
2182 commentX = wp.rcNormalPosition.left;
\r
2183 commentY = wp.rcNormalPosition.top;
\r
2184 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2185 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2188 if (editTagsDialog) {
\r
2189 GetWindowPlacement(editTagsDialog, &wp);
\r
2190 editTagsX = wp.rcNormalPosition.left;
\r
2191 editTagsY = wp.rcNormalPosition.top;
\r
2192 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2193 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2196 if (gameListDialog) {
\r
2197 GetWindowPlacement(gameListDialog, &wp);
\r
2198 gameListX = wp.rcNormalPosition.left;
\r
2199 gameListY = wp.rcNormalPosition.top;
\r
2200 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2201 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2204 /* [AS] Move history */
\r
2205 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2207 if( moveHistoryDialog ) {
\r
2208 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2209 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2210 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2211 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2212 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2215 /* [AS] Eval graph */
\r
2216 wpEvalGraph.visible = EvalGraphIsUp();
\r
2218 if( evalGraphDialog ) {
\r
2219 GetWindowPlacement(evalGraphDialog, &wp);
\r
2220 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2221 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2222 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2223 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2226 /* [AS] Engine output */
\r
2227 wpEngineOutput.visible = EngineOutputIsUp();
\r
2229 if( engineOutputDialog ) {
\r
2230 GetWindowPlacement(engineOutputDialog, &wp);
\r
2231 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2232 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2233 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2234 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2237 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2238 if (!ad->save) continue;
\r
2239 switch (ad->argType) {
\r
2242 char *p = *(char **)ad->argLoc;
\r
2243 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2244 /* Quote multiline values or \-containing values
\r
2245 with { } if possible */
\r
2246 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2248 /* Else quote with " " */
\r
2249 fprintf(f, "/%s=\"", ad->argName);
\r
2251 if (*p == '\n') fprintf(f, "\n");
\r
2252 else if (*p == '\r') fprintf(f, "\\r");
\r
2253 else if (*p == '\t') fprintf(f, "\\t");
\r
2254 else if (*p == '\b') fprintf(f, "\\b");
\r
2255 else if (*p == '\f') fprintf(f, "\\f");
\r
2256 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2257 else if (*p == '\"') fprintf(f, "\\\"");
\r
2258 else if (*p == '\\') fprintf(f, "\\\\");
\r
2262 fprintf(f, "\"\n");
\r
2267 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2270 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2273 fprintf(f, "/%s=%s\n", ad->argName,
\r
2274 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2277 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2280 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2284 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2285 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2286 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2291 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2292 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2293 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2294 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2295 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2296 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2297 (ta->effects) ? " " : "",
\r
2298 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2302 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2303 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2305 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2308 case ArgBoardSize:
\r
2309 fprintf(f, "/%s=%s\n", ad->argName,
\r
2310 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2315 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2316 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2317 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2318 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2319 ad->argName, mfp->faceName, mfp->pointSize,
\r
2320 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2321 mfp->bold ? "b" : "",
\r
2322 mfp->italic ? "i" : "",
\r
2323 mfp->underline ? "u" : "",
\r
2324 mfp->strikeout ? "s" : "");
\r
2328 case ArgCommSettings:
\r
2329 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2337 /*---------------------------------------------------------------------------*\
\r
2339 * GDI board drawing routines
\r
2341 \*---------------------------------------------------------------------------*/
\r
2343 /* [AS] Draw square using background texture */
\r
2344 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2349 return; /* Should never happen! */
\r
2352 SetGraphicsMode( dst, GM_ADVANCED );
\r
2359 /* X reflection */
\r
2364 x.eDx = (FLOAT) dw + dx - 1;
\r
2367 SetWorldTransform( dst, &x );
\r
2370 /* Y reflection */
\r
2376 x.eDy = (FLOAT) dh + dy - 1;
\r
2378 SetWorldTransform( dst, &x );
\r
2386 x.eDx = (FLOAT) dx;
\r
2387 x.eDy = (FLOAT) dy;
\r
2390 SetWorldTransform( dst, &x );
\r
2394 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2402 SetWorldTransform( dst, &x );
\r
2404 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2407 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2409 PM_WP = (int) WhitePawn,
\r
2410 PM_WN = (int) WhiteKnight,
\r
2411 PM_WB = (int) WhiteBishop,
\r
2412 PM_WR = (int) WhiteRook,
\r
2413 PM_WQ = (int) WhiteQueen,
\r
2414 PM_WF = (int) WhiteFerz,
\r
2415 PM_WW = (int) WhiteWazir,
\r
2416 PM_WE = (int) WhiteAlfil,
\r
2417 PM_WM = (int) WhiteMan,
\r
2418 PM_WO = (int) WhiteCannon,
\r
2419 PM_WU = (int) WhiteUnicorn,
\r
2420 PM_WH = (int) WhiteNightrider,
\r
2421 PM_WA = (int) WhiteAngel,
\r
2422 PM_WC = (int) WhiteMarshall,
\r
2423 PM_WAB = (int) WhiteCardinal,
\r
2424 PM_WD = (int) WhiteDragon,
\r
2425 PM_WL = (int) WhiteLance,
\r
2426 PM_WS = (int) WhiteCobra,
\r
2427 PM_WV = (int) WhiteFalcon,
\r
2428 PM_WSG = (int) WhiteSilver,
\r
2429 PM_WG = (int) WhiteGrasshopper,
\r
2430 PM_WK = (int) WhiteKing,
\r
2431 PM_BP = (int) BlackPawn,
\r
2432 PM_BN = (int) BlackKnight,
\r
2433 PM_BB = (int) BlackBishop,
\r
2434 PM_BR = (int) BlackRook,
\r
2435 PM_BQ = (int) BlackQueen,
\r
2436 PM_BF = (int) BlackFerz,
\r
2437 PM_BW = (int) BlackWazir,
\r
2438 PM_BE = (int) BlackAlfil,
\r
2439 PM_BM = (int) BlackMan,
\r
2440 PM_BO = (int) BlackCannon,
\r
2441 PM_BU = (int) BlackUnicorn,
\r
2442 PM_BH = (int) BlackNightrider,
\r
2443 PM_BA = (int) BlackAngel,
\r
2444 PM_BC = (int) BlackMarshall,
\r
2445 PM_BG = (int) BlackGrasshopper,
\r
2446 PM_BAB = (int) BlackCardinal,
\r
2447 PM_BD = (int) BlackDragon,
\r
2448 PM_BL = (int) BlackLance,
\r
2449 PM_BS = (int) BlackCobra,
\r
2450 PM_BV = (int) BlackFalcon,
\r
2451 PM_BSG = (int) BlackSilver,
\r
2452 PM_BK = (int) BlackKing
\r
2455 static HFONT hPieceFont = NULL;
\r
2456 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2457 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2458 static int fontBitmapSquareSize = 0;
\r
2459 static char pieceToFontChar[(int) EmptySquare] =
\r
2460 { 'p', 'n', 'b', 'r', 'q',
\r
2461 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2462 'k', 'o', 'm', 'v', 't', 'w',
\r
2463 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2466 extern BOOL SetCharTable( char *table, const char * map );
\r
2467 /* [HGM] moved to backend.c */
\r
2469 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2472 BYTE r1 = GetRValue( color );
\r
2473 BYTE g1 = GetGValue( color );
\r
2474 BYTE b1 = GetBValue( color );
\r
2480 /* Create a uniform background first */
\r
2481 hbrush = CreateSolidBrush( color );
\r
2482 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2483 FillRect( hdc, &rc, hbrush );
\r
2484 DeleteObject( hbrush );
\r
2487 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2488 int steps = squareSize / 2;
\r
2491 for( i=0; i<steps; i++ ) {
\r
2492 BYTE r = r1 - (r1-r2) * i / steps;
\r
2493 BYTE g = g1 - (g1-g2) * i / steps;
\r
2494 BYTE b = b1 - (b1-b2) * i / steps;
\r
2496 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2497 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2498 FillRect( hdc, &rc, hbrush );
\r
2499 DeleteObject(hbrush);
\r
2502 else if( mode == 2 ) {
\r
2503 /* Diagonal gradient, good more or less for every piece */
\r
2504 POINT triangle[3];
\r
2505 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2506 HBRUSH hbrush_old;
\r
2507 int steps = squareSize;
\r
2510 triangle[0].x = squareSize - steps;
\r
2511 triangle[0].y = squareSize;
\r
2512 triangle[1].x = squareSize;
\r
2513 triangle[1].y = squareSize;
\r
2514 triangle[2].x = squareSize;
\r
2515 triangle[2].y = squareSize - steps;
\r
2517 for( i=0; i<steps; i++ ) {
\r
2518 BYTE r = r1 - (r1-r2) * i / steps;
\r
2519 BYTE g = g1 - (g1-g2) * i / steps;
\r
2520 BYTE b = b1 - (b1-b2) * i / steps;
\r
2522 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2523 hbrush_old = SelectObject( hdc, hbrush );
\r
2524 Polygon( hdc, triangle, 3 );
\r
2525 SelectObject( hdc, hbrush_old );
\r
2526 DeleteObject(hbrush);
\r
2531 SelectObject( hdc, hpen );
\r
2536 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2537 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2538 piece: follow the steps as explained below.
\r
2540 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2544 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2548 int backColor = whitePieceColor;
\r
2549 int foreColor = blackPieceColor;
\r
2551 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2552 backColor = appData.fontBackColorWhite;
\r
2553 foreColor = appData.fontForeColorWhite;
\r
2555 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2556 backColor = appData.fontBackColorBlack;
\r
2557 foreColor = appData.fontForeColorBlack;
\r
2561 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2563 hbm_old = SelectObject( hdc, hbm );
\r
2567 rc.right = squareSize;
\r
2568 rc.bottom = squareSize;
\r
2570 /* Step 1: background is now black */
\r
2571 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2573 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2575 pt.x = (squareSize - sz.cx) / 2;
\r
2576 pt.y = (squareSize - sz.cy) / 2;
\r
2578 SetBkMode( hdc, TRANSPARENT );
\r
2579 SetTextColor( hdc, chroma );
\r
2580 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2581 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2583 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2584 /* Step 3: the area outside the piece is filled with white */
\r
2585 // FloodFill( hdc, 0, 0, chroma );
\r
2586 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2587 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2588 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2589 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2590 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2592 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2593 but if the start point is not inside the piece we're lost!
\r
2594 There should be a better way to do this... if we could create a region or path
\r
2595 from the fill operation we would be fine for example.
\r
2597 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2598 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2600 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2601 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2602 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2604 SelectObject( dc2, bm2 );
\r
2605 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2606 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2607 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2608 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2609 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2612 DeleteObject( bm2 );
\r
2615 SetTextColor( hdc, 0 );
\r
2617 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2618 draw the piece again in black for safety.
\r
2620 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2622 SelectObject( hdc, hbm_old );
\r
2624 if( hPieceMask[index] != NULL ) {
\r
2625 DeleteObject( hPieceMask[index] );
\r
2628 hPieceMask[index] = hbm;
\r
2631 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2633 SelectObject( hdc, hbm );
\r
2636 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2637 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2638 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2640 SelectObject( dc1, hPieceMask[index] );
\r
2641 SelectObject( dc2, bm2 );
\r
2642 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2643 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2646 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2647 the piece background and deletes (makes transparent) the rest.
\r
2648 Thanks to that mask, we are free to paint the background with the greates
\r
2649 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2650 We use this, to make gradients and give the pieces a "roundish" look.
\r
2652 SetPieceBackground( hdc, backColor, 2 );
\r
2653 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2657 DeleteObject( bm2 );
\r
2660 SetTextColor( hdc, foreColor );
\r
2661 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2663 SelectObject( hdc, hbm_old );
\r
2665 if( hPieceFace[index] != NULL ) {
\r
2666 DeleteObject( hPieceFace[index] );
\r
2669 hPieceFace[index] = hbm;
\r
2672 static int TranslatePieceToFontPiece( int piece )
\r
2702 case BlackMarshall:
\r
2706 case BlackNightrider:
\r
2712 case BlackUnicorn:
\r
2716 case BlackGrasshopper:
\r
2728 case BlackCardinal:
\r
2735 case WhiteMarshall:
\r
2739 case WhiteNightrider:
\r
2745 case WhiteUnicorn:
\r
2749 case WhiteGrasshopper:
\r
2761 case WhiteCardinal:
\r
2770 void CreatePiecesFromFont()
\r
2773 HDC hdc_window = NULL;
\r
2779 if( fontBitmapSquareSize < 0 ) {
\r
2780 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2784 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2785 fontBitmapSquareSize = -1;
\r
2789 if( fontBitmapSquareSize != squareSize ) {
\r
2790 hdc_window = GetDC( hwndMain );
\r
2791 hdc = CreateCompatibleDC( hdc_window );
\r
2793 if( hPieceFont != NULL ) {
\r
2794 DeleteObject( hPieceFont );
\r
2797 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2798 hPieceMask[i] = NULL;
\r
2799 hPieceFace[i] = NULL;
\r
2805 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2806 fontHeight = appData.fontPieceSize;
\r
2809 fontHeight = (fontHeight * squareSize) / 100;
\r
2811 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2813 lf.lfEscapement = 0;
\r
2814 lf.lfOrientation = 0;
\r
2815 lf.lfWeight = FW_NORMAL;
\r
2817 lf.lfUnderline = 0;
\r
2818 lf.lfStrikeOut = 0;
\r
2819 lf.lfCharSet = DEFAULT_CHARSET;
\r
2820 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2821 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2822 lf.lfQuality = PROOF_QUALITY;
\r
2823 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2824 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2825 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2827 hPieceFont = CreateFontIndirect( &lf );
\r
2829 if( hPieceFont == NULL ) {
\r
2830 fontBitmapSquareSize = -2;
\r
2833 /* Setup font-to-piece character table */
\r
2834 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2835 /* No (or wrong) global settings, try to detect the font */
\r
2836 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2838 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2840 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2841 /* DiagramTT* family */
\r
2842 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2844 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2845 /* Fairy symbols */
\r
2846 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2848 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2849 /* Good Companion (Some characters get warped as literal :-( */
\r
2850 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2851 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2852 SetCharTable(pieceToFontChar, s);
\r
2855 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2856 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2860 /* Create bitmaps */
\r
2861 hfont_old = SelectObject( hdc, hPieceFont );
\r
2863 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2864 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2865 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2866 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2867 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2868 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2869 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2870 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2909 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2910 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2913 SelectObject( hdc, hfont_old );
\r
2915 fontBitmapSquareSize = squareSize;
\r
2919 if( hdc != NULL ) {
\r
2923 if( hdc_window != NULL ) {
\r
2924 ReleaseDC( hwndMain, hdc_window );
\r
2929 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2933 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2934 if (gameInfo.event &&
\r
2935 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2936 strcmp(name, "k80s") == 0) {
\r
2937 strcpy(name, "tim");
\r
2939 return LoadBitmap(hinst, name);
\r
2943 /* Insert a color into the program's logical palette
\r
2944 structure. This code assumes the given color is
\r
2945 the result of the RGB or PALETTERGB macro, and it
\r
2946 knows how those macros work (which is documented).
\r
2949 InsertInPalette(COLORREF color)
\r
2951 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2953 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2954 DisplayFatalError("Too many colors", 0, 1);
\r
2955 pLogPal->palNumEntries--;
\r
2959 pe->peFlags = (char) 0;
\r
2960 pe->peRed = (char) (0xFF & color);
\r
2961 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2962 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2968 InitDrawingColors()
\r
2970 if (pLogPal == NULL) {
\r
2971 /* Allocate enough memory for a logical palette with
\r
2972 * PALETTESIZE entries and set the size and version fields
\r
2973 * of the logical palette structure.
\r
2975 pLogPal = (NPLOGPALETTE)
\r
2976 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2977 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2978 pLogPal->palVersion = 0x300;
\r
2980 pLogPal->palNumEntries = 0;
\r
2982 InsertInPalette(lightSquareColor);
\r
2983 InsertInPalette(darkSquareColor);
\r
2984 InsertInPalette(whitePieceColor);
\r
2985 InsertInPalette(blackPieceColor);
\r
2986 InsertInPalette(highlightSquareColor);
\r
2987 InsertInPalette(premoveHighlightColor);
\r
2989 /* create a logical color palette according the information
\r
2990 * in the LOGPALETTE structure.
\r
2992 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2994 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2995 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2996 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2997 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2998 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2999 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3001 /* [AS] Force rendering of the font-based pieces */
\r
3002 if( fontBitmapSquareSize > 0 ) {
\r
3003 fontBitmapSquareSize = 0;
\r
3009 BoardWidth(int boardSize, int n)
\r
3010 { /* [HGM] argument n added to allow different width and height */
\r
3011 int lineGap = sizeInfo[boardSize].lineGap;
\r
3013 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3014 lineGap = appData.overrideLineGap;
\r
3017 return (n + 1) * lineGap +
\r
3018 n * sizeInfo[boardSize].squareSize;
\r
3021 /* Respond to board resize by dragging edge */
\r
3023 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3025 BoardSize newSize = NUM_SIZES - 1;
\r
3026 static int recurse = 0;
\r
3027 if (IsIconic(hwndMain)) return;
\r
3028 if (recurse > 0) return;
\r
3030 while (newSize > 0) {
\r
3031 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3032 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3033 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3036 boardSize = newSize;
\r
3037 InitDrawingSizes(boardSize, flags);
\r
3044 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3046 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3047 ChessSquare piece;
\r
3048 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3050 SIZE clockSize, messageSize;
\r
3052 char buf[MSG_SIZ];
\r
3054 HMENU hmenu = GetMenu(hwndMain);
\r
3055 RECT crect, wrect;
\r
3057 LOGBRUSH logbrush;
\r
3059 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3060 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3062 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3063 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3065 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3066 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3067 squareSize = sizeInfo[boardSize].squareSize;
\r
3068 lineGap = sizeInfo[boardSize].lineGap;
\r
3069 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3071 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3072 lineGap = appData.overrideLineGap;
\r
3075 if (tinyLayout != oldTinyLayout) {
\r
3076 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3078 style &= ~WS_SYSMENU;
\r
3079 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3080 "&Minimize\tCtrl+F4");
\r
3082 style |= WS_SYSMENU;
\r
3083 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3085 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3087 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3088 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3089 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3091 DrawMenuBar(hwndMain);
\r
3094 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3095 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3097 /* Get text area sizes */
\r
3098 hdc = GetDC(hwndMain);
\r
3099 if (appData.clockMode) {
\r
3100 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3102 sprintf(buf, "White");
\r
3104 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3105 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3106 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3107 str = "We only care about the height here";
\r
3108 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3109 SelectObject(hdc, oldFont);
\r
3110 ReleaseDC(hwndMain, hdc);
\r
3112 /* Compute where everything goes */
\r
3113 if(first.programLogo || second.programLogo) {
\r
3114 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3115 logoHeight = 2*clockSize.cy;
\r
3116 leftLogoRect.left = OUTER_MARGIN;
\r
3117 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3118 leftLogoRect.top = OUTER_MARGIN;
\r
3119 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3121 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3122 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3123 rightLogoRect.top = OUTER_MARGIN;
\r
3124 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3127 blackRect.left = leftLogoRect.right;
\r
3128 blackRect.right = rightLogoRect.left;
\r
3129 blackRect.top = OUTER_MARGIN;
\r
3130 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3132 whiteRect.left = blackRect.left ;
\r
3133 whiteRect.right = blackRect.right;
\r
3134 whiteRect.top = blackRect.bottom;
\r
3135 whiteRect.bottom = leftLogoRect.bottom;
\r
3137 whiteRect.left = OUTER_MARGIN;
\r
3138 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3139 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3140 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3142 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3143 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3144 blackRect.top = whiteRect.top;
\r
3145 blackRect.bottom = whiteRect.bottom;
\r
3148 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3149 if (appData.showButtonBar) {
\r
3150 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3151 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3153 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3155 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3156 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3158 boardRect.left = OUTER_MARGIN;
\r
3159 boardRect.right = boardRect.left + boardWidth;
\r
3160 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3161 boardRect.bottom = boardRect.top + boardHeight;
\r
3163 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3164 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3165 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3166 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3167 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3168 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3169 GetWindowRect(hwndMain, &wrect);
\r
3170 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3171 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3172 /* compensate if menu bar wrapped */
\r
3173 GetClientRect(hwndMain, &crect);
\r
3174 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3175 winHeight += offby;
\r
3177 case WMSZ_TOPLEFT:
\r
3178 SetWindowPos(hwndMain, NULL,
\r
3179 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3180 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3183 case WMSZ_TOPRIGHT:
\r
3185 SetWindowPos(hwndMain, NULL,
\r
3186 wrect.left, wrect.bottom - winHeight,
\r
3187 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3190 case WMSZ_BOTTOMLEFT:
\r
3192 SetWindowPos(hwndMain, NULL,
\r
3193 wrect.right - winWidth, wrect.top,
\r
3194 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3197 case WMSZ_BOTTOMRIGHT:
\r
3201 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3202 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3207 for (i = 0; i < N_BUTTONS; i++) {
\r
3208 if (buttonDesc[i].hwnd != NULL) {
\r
3209 DestroyWindow(buttonDesc[i].hwnd);
\r
3210 buttonDesc[i].hwnd = NULL;
\r
3212 if (appData.showButtonBar) {
\r
3213 buttonDesc[i].hwnd =
\r
3214 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3215 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3216 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3217 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3218 (HMENU) buttonDesc[i].id,
\r
3219 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3221 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3222 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3223 MAKELPARAM(FALSE, 0));
\r
3225 if (buttonDesc[i].id == IDM_Pause)
\r
3226 hwndPause = buttonDesc[i].hwnd;
\r
3227 buttonDesc[i].wndproc = (WNDPROC)
\r
3228 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3231 if (gridPen != NULL) DeleteObject(gridPen);
\r
3232 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3233 if (premovePen != NULL) DeleteObject(premovePen);
\r
3234 if (lineGap != 0) {
\r
3235 logbrush.lbStyle = BS_SOLID;
\r
3236 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3238 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3239 lineGap, &logbrush, 0, NULL);
\r
3240 logbrush.lbColor = highlightSquareColor;
\r
3242 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3243 lineGap, &logbrush, 0, NULL);
\r
3245 logbrush.lbColor = premoveHighlightColor;
\r
3247 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3248 lineGap, &logbrush, 0, NULL);
\r
3250 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3251 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3252 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3253 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3254 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3255 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3256 BOARD_WIDTH * (squareSize + lineGap);
\r
3257 lineGap / 2 + (i * (squareSize + lineGap));
\r
3258 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3260 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3261 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3262 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3263 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3264 lineGap / 2 + (i * (squareSize + lineGap));
\r
3265 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3266 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3267 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3271 /* [HGM] Licensing requirement */
\r
3273 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3276 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3278 GothicPopUp( "", VariantNormal);
\r
3281 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3282 oldBoardSize = boardSize;
\r
3283 oldTinyLayout = tinyLayout;
\r
3285 /* Load piece bitmaps for this board size */
\r
3286 for (i=0; i<=2; i++) {
\r
3287 for (piece = WhitePawn;
\r
3288 (int) piece < (int) BlackPawn;
\r
3289 piece = (ChessSquare) ((int) piece + 1)) {
\r
3290 if (pieceBitmap[i][piece] != NULL)
\r
3291 DeleteObject(pieceBitmap[i][piece]);
\r
3295 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3296 // Orthodox Chess pieces
\r
3297 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3298 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3299 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3300 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3301 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3302 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3303 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3304 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3305 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3306 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3307 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3308 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3309 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3310 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3311 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3312 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3313 // in Shogi, Hijack the unused Queen for Lance
\r
3314 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3315 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3316 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3318 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3319 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3320 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3323 if(squareSize <= 72 && squareSize >= 33) {
\r
3324 /* A & C are available in most sizes now */
\r
3325 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3326 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3327 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3328 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3329 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3330 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3331 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3332 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3333 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3334 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3335 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3336 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3337 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3338 } else { // Smirf-like
\r
3339 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3343 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3344 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3345 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3346 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3347 } else { // WinBoard standard
\r
3348 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3349 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3350 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3355 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3356 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3357 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3358 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3359 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3360 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3361 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3362 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3363 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3364 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3365 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3366 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3367 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3368 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3369 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3370 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3371 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3372 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3373 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3374 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3375 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3376 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3377 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3378 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3379 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3380 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3381 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3382 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3383 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3384 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3385 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3387 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3388 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3389 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3390 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3391 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3392 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3393 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3394 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3395 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3396 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3397 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3398 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3399 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3404 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3405 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3406 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3407 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3408 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3409 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3410 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3411 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3412 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3415 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3416 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3417 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3418 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3419 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3420 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3421 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3422 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3423 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3424 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3425 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3426 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3427 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3428 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3429 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3433 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3434 /* special Shogi support in this size */
\r
3435 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3436 for (piece = WhitePawn;
\r
3437 (int) piece < (int) BlackPawn;
\r
3438 piece = (ChessSquare) ((int) piece + 1)) {
\r
3439 if (pieceBitmap[i][piece] != NULL)
\r
3440 DeleteObject(pieceBitmap[i][piece]);
\r
3443 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3444 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3445 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3446 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3447 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3448 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3449 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3450 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3451 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3452 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3453 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3454 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3455 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3456 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3457 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3458 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3459 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3460 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3461 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3462 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3463 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3464 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3465 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3466 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3467 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3468 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3469 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3470 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3471 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3472 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3473 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3474 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3475 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3476 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3477 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3478 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3479 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3490 PieceBitmap(ChessSquare p, int kind)
\r
3492 if ((int) p >= (int) BlackPawn)
\r
3493 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3495 return pieceBitmap[kind][(int) p];
\r
3498 /***************************************************************/
\r
3500 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3501 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3503 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3504 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3508 SquareToPos(int row, int column, int * x, int * y)
\r
3511 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3512 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3514 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3515 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3520 DrawCoordsOnDC(HDC hdc)
\r
3522 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
3523 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
3524 char str[2] = { NULLCHAR, NULLCHAR };
\r
3525 int oldMode, oldAlign, x, y, start, i;
\r
3529 if (!appData.showCoords)
\r
3532 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3534 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3535 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3536 oldAlign = GetTextAlign(hdc);
\r
3537 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3539 y = boardRect.top + lineGap;
\r
3540 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3542 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3543 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3544 str[0] = files[start + i];
\r
3545 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3546 y += squareSize + lineGap;
\r
3549 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3551 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3552 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3553 str[0] = ranks[start + i];
\r
3554 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3555 x += squareSize + lineGap;
\r
3558 SelectObject(hdc, oldBrush);
\r
3559 SetBkMode(hdc, oldMode);
\r
3560 SetTextAlign(hdc, oldAlign);
\r
3561 SelectObject(hdc, oldFont);
\r
3565 DrawGridOnDC(HDC hdc)
\r
3569 if (lineGap != 0) {
\r
3570 oldPen = SelectObject(hdc, gridPen);
\r
3571 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3572 SelectObject(hdc, oldPen);
\r
3576 #define HIGHLIGHT_PEN 0
\r
3577 #define PREMOVE_PEN 1
\r
3580 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3583 HPEN oldPen, hPen;
\r
3584 if (lineGap == 0) return;
\r
3586 x1 = boardRect.left +
\r
3587 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3588 y1 = boardRect.top +
\r
3589 lineGap/2 + y * (squareSize + lineGap);
\r
3591 x1 = boardRect.left +
\r
3592 lineGap/2 + x * (squareSize + lineGap);
\r
3593 y1 = boardRect.top +
\r
3594 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3596 hPen = pen ? premovePen : highlightPen;
\r
3597 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3598 MoveToEx(hdc, x1, y1, NULL);
\r
3599 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3600 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3601 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3602 LineTo(hdc, x1, y1);
\r
3603 SelectObject(hdc, oldPen);
\r
3607 DrawHighlightsOnDC(HDC hdc)
\r
3610 for (i=0; i<2; i++) {
\r
3611 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3612 DrawHighlightOnDC(hdc, TRUE,
\r
3613 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3616 for (i=0; i<2; i++) {
\r
3617 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3618 premoveHighlightInfo.sq[i].y >= 0) {
\r
3619 DrawHighlightOnDC(hdc, TRUE,
\r
3620 premoveHighlightInfo.sq[i].x,
\r
3621 premoveHighlightInfo.sq[i].y,
\r
3627 /* Note: sqcolor is used only in monoMode */
\r
3628 /* Note that this code is largely duplicated in woptions.c,
\r
3629 function DrawSampleSquare, so that needs to be updated too */
\r
3631 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3633 HBITMAP oldBitmap;
\r
3637 if (appData.blindfold) return;
\r
3639 /* [AS] Use font-based pieces if needed */
\r
3640 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3641 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3642 CreatePiecesFromFont();
\r
3644 if( fontBitmapSquareSize == squareSize ) {
\r
3645 int index = TranslatePieceToFontPiece(piece);
\r
3647 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3651 squareSize, squareSize,
\r
3656 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3660 squareSize, squareSize,
\r
3669 if (appData.monoMode) {
\r
3670 SelectObject(tmphdc, PieceBitmap(piece,
\r
3671 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3672 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3673 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3675 tmpSize = squareSize;
\r
3677 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3678 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3679 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3680 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3681 x += (squareSize - minorSize)>>1;
\r
3682 y += squareSize - minorSize - 2;
\r
3683 tmpSize = minorSize;
\r
3685 if (color || appData.allWhite ) {
\r
3686 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3688 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3689 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3690 if(appData.upsideDown && color==flipView)
\r
3691 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3693 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3695 /* Use black piece color for outline of white pieces */
\r
3696 /* Not sure this looks really good (though xboard does it).
\r
3697 Maybe better to have another selectable color, default black */
\r
3698 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3699 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3700 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3702 /* Use black for outline of white pieces */
\r
3703 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3704 if(appData.upsideDown && color==flipView)
\r
3705 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3707 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3711 /* Use white piece color for details of black pieces */
\r
3712 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3713 WHITE_PIECE ones aren't always the right shape. */
\r
3714 /* Not sure this looks really good (though xboard does it).
\r
3715 Maybe better to have another selectable color, default medium gray? */
\r
3716 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3717 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3718 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3719 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3720 SelectObject(hdc, blackPieceBrush);
\r
3721 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3723 /* Use square color for details of black pieces */
\r
3724 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3725 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3726 if(appData.upsideDown && !flipView)
\r
3727 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3729 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3732 SelectObject(hdc, oldBrush);
\r
3733 SelectObject(tmphdc, oldBitmap);
\r
3737 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3738 int GetBackTextureMode( int algo )
\r
3740 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3744 case BACK_TEXTURE_MODE_PLAIN:
\r
3745 result = 1; /* Always use identity map */
\r
3747 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3748 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3756 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3757 to handle redraws cleanly (as random numbers would always be different).
\r
3759 VOID RebuildTextureSquareInfo()
\r
3769 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3771 if( liteBackTexture != NULL ) {
\r
3772 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3773 lite_w = bi.bmWidth;
\r
3774 lite_h = bi.bmHeight;
\r
3778 if( darkBackTexture != NULL ) {
\r
3779 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3780 dark_w = bi.bmWidth;
\r
3781 dark_h = bi.bmHeight;
\r
3785 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3786 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3787 if( (col + row) & 1 ) {
\r
3789 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3790 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3791 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3792 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3797 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3798 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3799 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3800 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3807 /* [AS] Arrow highlighting support */
\r
3809 static int A_WIDTH = 5; /* Width of arrow body */
\r
3811 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3812 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3814 static double Sqr( double x )
\r
3819 static int Round( double x )
\r
3821 return (int) (x + 0.5);
\r
3824 /* Draw an arrow between two points using current settings */
\r
3825 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3828 double dx, dy, j, k, x, y;
\r
3830 if( d_x == s_x ) {
\r
3831 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3833 arrow[0].x = s_x + A_WIDTH;
\r
3836 arrow[1].x = s_x + A_WIDTH;
\r
3837 arrow[1].y = d_y - h;
\r
3839 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3840 arrow[2].y = d_y - h;
\r
3845 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3846 arrow[4].y = d_y - h;
\r
3848 arrow[5].x = s_x - A_WIDTH;
\r
3849 arrow[5].y = d_y - h;
\r
3851 arrow[6].x = s_x - A_WIDTH;
\r
3854 else if( d_y == s_y ) {
\r
3855 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3858 arrow[0].y = s_y + A_WIDTH;
\r
3860 arrow[1].x = d_x - w;
\r
3861 arrow[1].y = s_y + A_WIDTH;
\r
3863 arrow[2].x = d_x - w;
\r
3864 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3869 arrow[4].x = d_x - w;
\r
3870 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3872 arrow[5].x = d_x - w;
\r
3873 arrow[5].y = s_y - A_WIDTH;
\r
3876 arrow[6].y = s_y - A_WIDTH;
\r
3879 /* [AS] Needed a lot of paper for this! :-) */
\r
3880 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3881 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3883 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3885 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3890 arrow[0].x = Round(x - j);
\r
3891 arrow[0].y = Round(y + j*dx);
\r
3893 arrow[1].x = Round(x + j);
\r
3894 arrow[1].y = Round(y - j*dx);
\r
3897 x = (double) d_x - k;
\r
3898 y = (double) d_y - k*dy;
\r
3901 x = (double) d_x + k;
\r
3902 y = (double) d_y + k*dy;
\r
3905 arrow[2].x = Round(x + j);
\r
3906 arrow[2].y = Round(y - j*dx);
\r
3908 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3909 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3914 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3915 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3917 arrow[6].x = Round(x - j);
\r
3918 arrow[6].y = Round(y + j*dx);
\r
3921 Polygon( hdc, arrow, 7 );
\r
3924 /* [AS] Draw an arrow between two squares */
\r
3925 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3927 int s_x, s_y, d_x, d_y;
\r
3934 if( s_col == d_col && s_row == d_row ) {
\r
3938 /* Get source and destination points */
\r
3939 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3940 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3943 d_y += squareSize / 4;
\r
3945 else if( d_y < s_y ) {
\r
3946 d_y += 3 * squareSize / 4;
\r
3949 d_y += squareSize / 2;
\r
3953 d_x += squareSize / 4;
\r
3955 else if( d_x < s_x ) {
\r
3956 d_x += 3 * squareSize / 4;
\r
3959 d_x += squareSize / 2;
\r
3962 s_x += squareSize / 2;
\r
3963 s_y += squareSize / 2;
\r
3965 /* Adjust width */
\r
3966 A_WIDTH = squareSize / 14;
\r
3969 stLB.lbStyle = BS_SOLID;
\r
3970 stLB.lbColor = appData.highlightArrowColor;
\r
3973 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3974 holdpen = SelectObject( hdc, hpen );
\r
3975 hbrush = CreateBrushIndirect( &stLB );
\r
3976 holdbrush = SelectObject( hdc, hbrush );
\r
3978 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3980 SelectObject( hdc, holdpen );
\r
3981 SelectObject( hdc, holdbrush );
\r
3982 DeleteObject( hpen );
\r
3983 DeleteObject( hbrush );
\r
3986 BOOL HasHighlightInfo()
\r
3988 BOOL result = FALSE;
\r
3990 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3991 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3999 BOOL IsDrawArrowEnabled()
\r
4001 BOOL result = FALSE;
\r
4003 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4010 VOID DrawArrowHighlight( HDC hdc )
\r
4012 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4013 DrawArrowBetweenSquares( hdc,
\r
4014 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4015 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4019 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4021 HRGN result = NULL;
\r
4023 if( HasHighlightInfo() ) {
\r
4024 int x1, y1, x2, y2;
\r
4025 int sx, sy, dx, dy;
\r
4027 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4028 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4030 sx = MIN( x1, x2 );
\r
4031 sy = MIN( y1, y2 );
\r
4032 dx = MAX( x1, x2 ) + squareSize;
\r
4033 dy = MAX( y1, y2 ) + squareSize;
\r
4035 result = CreateRectRgn( sx, sy, dx, dy );
\r
4042 Warning: this function modifies the behavior of several other functions.
\r
4044 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4045 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4046 repaint is scattered all over the place, which is not good for features such as
\r
4047 "arrow highlighting" that require a full repaint of the board.
\r
4049 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4050 user interaction, when speed is not so important) but especially to avoid errors
\r
4051 in the displayed graphics.
\r
4053 In such patched places, I always try refer to this function so there is a single
\r
4054 place to maintain knowledge.
\r
4056 To restore the original behavior, just return FALSE unconditionally.
\r
4058 BOOL IsFullRepaintPreferrable()
\r
4060 BOOL result = FALSE;
\r
4062 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4063 /* Arrow may appear on the board */
\r
4071 This function is called by DrawPosition to know whether a full repaint must
\r
4074 Only DrawPosition may directly call this function, which makes use of
\r
4075 some state information. Other function should call DrawPosition specifying
\r
4076 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4078 BOOL DrawPositionNeedsFullRepaint()
\r
4080 BOOL result = FALSE;
\r
4083 Probably a slightly better policy would be to trigger a full repaint
\r
4084 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4085 but animation is fast enough that it's difficult to notice.
\r
4087 if( animInfo.piece == EmptySquare ) {
\r
4088 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4097 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4099 int row, column, x, y, square_color, piece_color;
\r
4100 ChessSquare piece;
\r
4102 HDC texture_hdc = NULL;
\r
4104 /* [AS] Initialize background textures if needed */
\r
4105 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4106 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4107 if( backTextureSquareSize != squareSize
\r
4108 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4109 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4110 backTextureSquareSize = squareSize;
\r
4111 RebuildTextureSquareInfo();
\r
4114 texture_hdc = CreateCompatibleDC( hdc );
\r
4117 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4118 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4120 SquareToPos(row, column, &x, &y);
\r
4122 piece = board[row][column];
\r
4124 square_color = ((column + row) % 2) == 1;
\r
4125 if( gameInfo.variant == VariantXiangqi ) {
\r
4126 square_color = !InPalace(row, column);
\r
4127 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4128 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4130 piece_color = (int) piece < (int) BlackPawn;
\r
4133 /* [HGM] holdings file: light square or black */
\r
4134 if(column == BOARD_LEFT-2) {
\r
4135 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4138 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4142 if(column == BOARD_RGHT + 1 ) {
\r
4143 if( row < gameInfo.holdingsSize )
\r
4146 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4150 if(column == BOARD_LEFT-1 ) /* left align */
\r
4151 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4152 else if( column == BOARD_RGHT) /* right align */
\r
4153 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4155 if (appData.monoMode) {
\r
4156 if (piece == EmptySquare) {
\r
4157 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4158 square_color ? WHITENESS : BLACKNESS);
\r
4160 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4163 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4164 /* [AS] Draw the square using a texture bitmap */
\r
4165 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4166 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4167 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4170 squareSize, squareSize,
\r
4173 backTextureSquareInfo[r][c].mode,
\r
4174 backTextureSquareInfo[r][c].x,
\r
4175 backTextureSquareInfo[r][c].y );
\r
4177 SelectObject( texture_hdc, hbm );
\r
4179 if (piece != EmptySquare) {
\r
4180 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4184 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4186 oldBrush = SelectObject(hdc, brush );
\r
4187 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4188 SelectObject(hdc, oldBrush);
\r
4189 if (piece != EmptySquare)
\r
4190 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4195 if( texture_hdc != NULL ) {
\r
4196 DeleteDC( texture_hdc );
\r
4200 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4201 void fputDW(FILE *f, int x)
\r
4203 fputc(x & 255, f);
\r
4204 fputc(x>>8 & 255, f);
\r
4205 fputc(x>>16 & 255, f);
\r
4206 fputc(x>>24 & 255, f);
\r
4209 #define MAX_CLIPS 200 /* more than enough */
\r
4212 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4214 HBITMAP bufferBitmap;
\r
4219 int w = 100, h = 50;
\r
4221 if(cps->programLogo == NULL) return;
\r
4222 // GetClientRect(hwndMain, &Rect);
\r
4223 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4224 // Rect.bottom-Rect.top+1);
\r
4225 tmphdc = CreateCompatibleDC(hdc);
\r
4226 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4227 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4231 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4232 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4233 SelectObject(tmphdc, hbm);
\r
4238 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4240 static Board lastReq, lastDrawn;
\r
4241 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4242 static int lastDrawnFlipView = 0;
\r
4243 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4244 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4247 HBITMAP bufferBitmap;
\r
4248 HBITMAP oldBitmap;
\r
4250 HRGN clips[MAX_CLIPS];
\r
4251 ChessSquare dragged_piece = EmptySquare;
\r
4253 /* I'm undecided on this - this function figures out whether a full
\r
4254 * repaint is necessary on its own, so there's no real reason to have the
\r
4255 * caller tell it that. I think this can safely be set to FALSE - but
\r
4256 * if we trust the callers not to request full repaints unnessesarily, then
\r
4257 * we could skip some clipping work. In other words, only request a full
\r
4258 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4259 * gamestart and similar) --Hawk
\r
4261 Boolean fullrepaint = repaint;
\r
4263 if( DrawPositionNeedsFullRepaint() ) {
\r
4264 fullrepaint = TRUE;
\r
4268 if( fullrepaint ) {
\r
4269 static int repaint_count = 0;
\r
4273 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4274 OutputDebugString( buf );
\r
4278 if (board == NULL) {
\r
4279 if (!lastReqValid) {
\r
4284 CopyBoard(lastReq, board);
\r
4288 if (doingSizing) {
\r
4292 if (IsIconic(hwndMain)) {
\r
4296 if (hdc == NULL) {
\r
4297 hdc = GetDC(hwndMain);
\r
4298 if (!appData.monoMode) {
\r
4299 SelectPalette(hdc, hPal, FALSE);
\r
4300 RealizePalette(hdc);
\r
4304 releaseDC = FALSE;
\r
4308 fprintf(debugFP, "*******************************\n"
\r
4310 "dragInfo.from (%d,%d)\n"
\r
4311 "dragInfo.start (%d,%d)\n"
\r
4312 "dragInfo.pos (%d,%d)\n"
\r
4313 "dragInfo.lastpos (%d,%d)\n",
\r
4314 repaint ? "TRUE" : "FALSE",
\r
4315 dragInfo.from.x, dragInfo.from.y,
\r
4316 dragInfo.start.x, dragInfo.start.y,
\r
4317 dragInfo.pos.x, dragInfo.pos.y,
\r
4318 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4319 fprintf(debugFP, "prev: ");
\r
4320 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4321 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4322 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4325 fprintf(debugFP, "\n");
\r
4326 fprintf(debugFP, "board: ");
\r
4327 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4328 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4329 fprintf(debugFP, "%d ", board[row][column]);
\r
4332 fprintf(debugFP, "\n");
\r
4336 /* Create some work-DCs */
\r
4337 hdcmem = CreateCompatibleDC(hdc);
\r
4338 tmphdc = CreateCompatibleDC(hdc);
\r
4340 /* If dragging is in progress, we temporarely remove the piece */
\r
4341 /* [HGM] or temporarily decrease count if stacked */
\r
4342 /* !! Moved to before board compare !! */
\r
4343 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4344 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4345 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4346 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4347 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4349 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4350 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4351 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4353 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4356 /* Figure out which squares need updating by comparing the
\r
4357 * newest board with the last drawn board and checking if
\r
4358 * flipping has changed.
\r
4360 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4361 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4362 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4363 if (lastDrawn[row][column] != board[row][column]) {
\r
4364 SquareToPos(row, column, &x, &y);
\r
4365 clips[num_clips++] =
\r
4366 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4370 for (i=0; i<2; i++) {
\r
4371 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4372 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4373 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4374 lastDrawnHighlight.sq[i].y >= 0) {
\r
4375 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4376 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4377 clips[num_clips++] =
\r
4378 CreateRectRgn(x - lineGap, y - lineGap,
\r
4379 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4381 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4382 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4383 clips[num_clips++] =
\r
4384 CreateRectRgn(x - lineGap, y - lineGap,
\r
4385 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4389 for (i=0; i<2; i++) {
\r
4390 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4391 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4392 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4393 lastDrawnPremove.sq[i].y >= 0) {
\r
4394 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4395 lastDrawnPremove.sq[i].x, &x, &y);
\r
4396 clips[num_clips++] =
\r
4397 CreateRectRgn(x - lineGap, y - lineGap,
\r
4398 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4400 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4401 premoveHighlightInfo.sq[i].y >= 0) {
\r
4402 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4403 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4404 clips[num_clips++] =
\r
4405 CreateRectRgn(x - lineGap, y - lineGap,
\r
4406 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4411 fullrepaint = TRUE;
\r
4414 /* Create a buffer bitmap - this is the actual bitmap
\r
4415 * being written to. When all the work is done, we can
\r
4416 * copy it to the real DC (the screen). This avoids
\r
4417 * the problems with flickering.
\r
4419 GetClientRect(hwndMain, &Rect);
\r
4420 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4421 Rect.bottom-Rect.top+1);
\r
4422 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4423 if (!appData.monoMode) {
\r
4424 SelectPalette(hdcmem, hPal, FALSE);
\r
4427 /* Create clips for dragging */
\r
4428 if (!fullrepaint) {
\r
4429 if (dragInfo.from.x >= 0) {
\r
4430 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4431 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4433 if (dragInfo.start.x >= 0) {
\r
4434 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4435 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4437 if (dragInfo.pos.x >= 0) {
\r
4438 x = dragInfo.pos.x - squareSize / 2;
\r
4439 y = dragInfo.pos.y - squareSize / 2;
\r
4440 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4442 if (dragInfo.lastpos.x >= 0) {
\r
4443 x = dragInfo.lastpos.x - squareSize / 2;
\r
4444 y = dragInfo.lastpos.y - squareSize / 2;
\r
4445 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4449 /* Are we animating a move?
\r
4451 * - remove the piece from the board (temporarely)
\r
4452 * - calculate the clipping region
\r
4454 if (!fullrepaint) {
\r
4455 if (animInfo.piece != EmptySquare) {
\r
4456 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4457 x = boardRect.left + animInfo.lastpos.x;
\r
4458 y = boardRect.top + animInfo.lastpos.y;
\r
4459 x2 = boardRect.left + animInfo.pos.x;
\r
4460 y2 = boardRect.top + animInfo.pos.y;
\r
4461 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4462 /* Slight kludge. The real problem is that after AnimateMove is
\r
4463 done, the position on the screen does not match lastDrawn.
\r
4464 This currently causes trouble only on e.p. captures in
\r
4465 atomic, where the piece moves to an empty square and then
\r
4466 explodes. The old and new positions both had an empty square
\r
4467 at the destination, but animation has drawn a piece there and
\r
4468 we have to remember to erase it. */
\r
4469 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4473 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4474 if (num_clips == 0)
\r
4475 fullrepaint = TRUE;
\r
4477 /* Set clipping on the memory DC */
\r
4478 if (!fullrepaint) {
\r
4479 SelectClipRgn(hdcmem, clips[0]);
\r
4480 for (x = 1; x < num_clips; x++) {
\r
4481 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4482 abort(); // this should never ever happen!
\r
4486 /* Do all the drawing to the memory DC */
\r
4487 DrawGridOnDC(hdcmem);
\r
4488 DrawHighlightsOnDC(hdcmem);
\r
4489 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4492 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4493 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4496 if( appData.highlightMoveWithArrow ) {
\r
4497 DrawArrowHighlight(hdcmem);
\r
4500 DrawCoordsOnDC(hdcmem);
\r
4502 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4503 /* to make sure lastDrawn contains what is actually drawn */
\r
4505 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4506 if (dragged_piece != EmptySquare) {
\r
4507 /* [HGM] or restack */
\r
4508 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4509 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4511 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4512 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4513 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4514 x = dragInfo.pos.x - squareSize / 2;
\r
4515 y = dragInfo.pos.y - squareSize / 2;
\r
4516 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4517 ((int) dragged_piece < (int) BlackPawn),
\r
4518 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4521 /* Put the animated piece back into place and draw it */
\r
4522 if (animInfo.piece != EmptySquare) {
\r
4523 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4524 x = boardRect.left + animInfo.pos.x;
\r
4525 y = boardRect.top + animInfo.pos.y;
\r
4526 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4527 ((int) animInfo.piece < (int) BlackPawn),
\r
4528 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4531 /* Release the bufferBitmap by selecting in the old bitmap
\r
4532 * and delete the memory DC
\r
4534 SelectObject(hdcmem, oldBitmap);
\r
4537 /* Set clipping on the target DC */
\r
4538 if (!fullrepaint) {
\r
4539 SelectClipRgn(hdc, clips[0]);
\r
4540 for (x = 1; x < num_clips; x++) {
\r
4541 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4542 abort(); // this should never ever happen!
\r
4546 /* Copy the new bitmap onto the screen in one go.
\r
4547 * This way we avoid any flickering
\r
4549 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4550 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4551 boardRect.right - boardRect.left,
\r
4552 boardRect.bottom - boardRect.top,
\r
4553 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4554 if(saveDiagFlag) {
\r
4555 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4556 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4558 GetObject(bufferBitmap, sizeof(b), &b);
\r
4559 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4560 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4561 bih.biWidth = b.bmWidth;
\r
4562 bih.biHeight = b.bmHeight;
\r
4564 bih.biBitCount = b.bmBitsPixel;
\r
4565 bih.biCompression = 0;
\r
4566 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4567 bih.biXPelsPerMeter = 0;
\r
4568 bih.biYPelsPerMeter = 0;
\r
4569 bih.biClrUsed = 0;
\r
4570 bih.biClrImportant = 0;
\r
4571 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4572 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4573 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4574 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4577 wb = b.bmWidthBytes;
\r
4579 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4580 int k = ((int*) pData)[i];
\r
4581 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4582 if(j >= 16) break;
\r
4584 if(j >= nrColors) nrColors = j+1;
\r
4586 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4588 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4589 for(w=0; w<(wb>>2); w+=2) {
\r
4590 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4591 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4592 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4593 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4594 pData[p++] = m | j<<4;
\r
4596 while(p&3) pData[p++] = 0;
\r
4599 wb = (wb+31>>5)<<2;
\r
4601 // write BITMAPFILEHEADER
\r
4602 fprintf(diagFile, "BM");
\r
4603 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4604 fputDW(diagFile, 0);
\r
4605 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4606 // write BITMAPINFOHEADER
\r
4607 fputDW(diagFile, 40);
\r
4608 fputDW(diagFile, b.bmWidth);
\r
4609 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4610 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4611 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4612 fputDW(diagFile, 0);
\r
4613 fputDW(diagFile, 0);
\r
4614 fputDW(diagFile, 0);
\r
4615 fputDW(diagFile, 0);
\r
4616 fputDW(diagFile, 0);
\r
4617 fputDW(diagFile, 0);
\r
4618 // write color table
\r
4620 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4621 // write bitmap data
\r
4622 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4623 fputc(pData[i], diagFile);
\r
4628 SelectObject(tmphdc, oldBitmap);
\r
4630 /* Massive cleanup */
\r
4631 for (x = 0; x < num_clips; x++)
\r
4632 DeleteObject(clips[x]);
\r
4635 DeleteObject(bufferBitmap);
\r
4638 ReleaseDC(hwndMain, hdc);
\r
4640 if (lastDrawnFlipView != flipView) {
\r
4642 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4644 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4647 /* CopyBoard(lastDrawn, board);*/
\r
4648 lastDrawnHighlight = highlightInfo;
\r
4649 lastDrawnPremove = premoveHighlightInfo;
\r
4650 lastDrawnFlipView = flipView;
\r
4651 lastDrawnValid = 1;
\r
4654 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4662 saveDiagFlag = 1; diagFile = f;
\r
4663 HDCDrawPosition(NULL, TRUE, NULL);
\r
4667 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4674 /*---------------------------------------------------------------------------*\
\r
4675 | CLIENT PAINT PROCEDURE
\r
4676 | This is the main event-handler for the WM_PAINT message.
\r
4678 \*---------------------------------------------------------------------------*/
\r
4680 PaintProc(HWND hwnd)
\r
4686 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4687 if (IsIconic(hwnd)) {
\r
4688 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4690 if (!appData.monoMode) {
\r
4691 SelectPalette(hdc, hPal, FALSE);
\r
4692 RealizePalette(hdc);
\r
4694 HDCDrawPosition(hdc, 1, NULL);
\r
4696 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4697 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4698 ETO_CLIPPED|ETO_OPAQUE,
\r
4699 &messageRect, messageText, strlen(messageText), NULL);
\r
4700 SelectObject(hdc, oldFont);
\r
4701 DisplayBothClocks();
\r
4703 EndPaint(hwnd,&ps);
\r
4711 * If the user selects on a border boundary, return -1; if off the board,
\r
4712 * return -2. Otherwise map the event coordinate to the square.
\r
4713 * The offset boardRect.left or boardRect.top must already have been
\r
4714 * subtracted from x.
\r
4717 EventToSquare(int x)
\r
4724 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4726 x /= (squareSize + lineGap);
\r
4727 if (x >= BOARD_SIZE)
\r
4738 DropEnable dropEnables[] = {
\r
4739 { 'P', DP_Pawn, "Pawn" },
\r
4740 { 'N', DP_Knight, "Knight" },
\r
4741 { 'B', DP_Bishop, "Bishop" },
\r
4742 { 'R', DP_Rook, "Rook" },
\r
4743 { 'Q', DP_Queen, "Queen" },
\r
4747 SetupDropMenu(HMENU hmenu)
\r
4749 int i, count, enable;
\r
4751 extern char white_holding[], black_holding[];
\r
4752 char item[MSG_SIZ];
\r
4754 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4755 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4756 dropEnables[i].piece);
\r
4758 while (p && *p++ == dropEnables[i].piece) count++;
\r
4759 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4760 enable = count > 0 || !appData.testLegality
\r
4761 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4762 && !appData.icsActive);
\r
4763 ModifyMenu(hmenu, dropEnables[i].command,
\r
4764 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4765 dropEnables[i].command, item);
\r
4769 static int fromX = -1, fromY = -1, toX, toY;
\r
4771 /* Event handler for mouse messages */
\r
4773 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4777 static int recursive = 0;
\r
4779 BOOLEAN needsRedraw = FALSE;
\r
4780 BOOLEAN saveAnimate;
\r
4781 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4782 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4783 ChessMove moveType;
\r
4786 if (message == WM_MBUTTONUP) {
\r
4787 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4788 to the middle button: we simulate pressing the left button too!
\r
4790 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4791 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4797 pt.x = LOWORD(lParam);
\r
4798 pt.y = HIWORD(lParam);
\r
4799 x = EventToSquare(pt.x - boardRect.left);
\r
4800 y = EventToSquare(pt.y - boardRect.top);
\r
4801 if (!flipView && y >= 0) {
\r
4802 y = BOARD_HEIGHT - 1 - y;
\r
4804 if (flipView && x >= 0) {
\r
4805 x = BOARD_WIDTH - 1 - x;
\r
4808 switch (message) {
\r
4809 case WM_LBUTTONDOWN:
\r
4810 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4811 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4812 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4813 if(gameInfo.holdingsWidth &&
\r
4814 (WhiteOnMove(currentMove)
\r
4815 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4816 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4817 // click in right holdings, for determining promotion piece
\r
4818 ChessSquare p = boards[currentMove][y][x];
\r
4819 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4820 if(p != EmptySquare) {
\r
4821 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4822 fromX = fromY = -1;
\r
4826 DrawPosition(FALSE, boards[currentMove]);
\r
4830 sameAgain = FALSE;
\r
4832 /* Downclick vertically off board; check if on clock */
\r
4833 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4834 if (gameMode == EditPosition) {
\r
4835 SetWhiteToPlayEvent();
\r
4836 } else if (gameMode == IcsPlayingBlack ||
\r
4837 gameMode == MachinePlaysWhite) {
\r
4839 } else if (gameMode == EditGame) {
\r
4840 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4842 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4843 if (gameMode == EditPosition) {
\r
4844 SetBlackToPlayEvent();
\r
4845 } else if (gameMode == IcsPlayingWhite ||
\r
4846 gameMode == MachinePlaysBlack) {
\r
4848 } else if (gameMode == EditGame) {
\r
4849 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4852 if (!appData.highlightLastMove) {
\r
4853 ClearHighlights();
\r
4854 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4856 fromX = fromY = -1;
\r
4857 dragInfo.start.x = dragInfo.start.y = -1;
\r
4858 dragInfo.from = dragInfo.start;
\r
4860 } else if (x < 0 || y < 0
\r
4861 /* [HGM] block clicks between board and holdings */
\r
4862 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4863 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4864 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4865 /* EditPosition, empty square, or different color piece;
\r
4866 click-click move is possible */
\r
4869 } else if (fromX == x && fromY == y) {
\r
4870 /* Downclick on same square again */
\r
4871 ClearHighlights();
\r
4872 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4873 sameAgain = TRUE;
\r
4874 } else if (fromX != -1 &&
\r
4875 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4877 /* Downclick on different square. */
\r
4878 /* [HGM] if on holdings file, should count as new first click ! */
\r
4879 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4882 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4883 to make sure move is legal before showing promotion popup */
\r
4884 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4885 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4886 fromX = fromY = -1;
\r
4887 ClearHighlights();
\r
4888 DrawPosition(FALSE, boards[currentMove]);
\r
4891 if(moveType != ImpossibleMove) {
\r
4892 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4893 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4894 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4895 appData.alwaysPromoteToQueen) {
\r
4896 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4897 if (!appData.highlightLastMove) {
\r
4898 ClearHighlights();
\r
4899 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4902 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4903 SetHighlights(fromX, fromY, toX, toY);
\r
4904 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4905 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4906 If promotion to Q is legal, all are legal! */
\r
4907 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4908 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4909 // kludge to temporarily execute move on display, wthout promotng yet
\r
4910 promotionChoice = TRUE;
\r
4911 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4912 boards[currentMove][toY][toX] = p;
\r
4913 DrawPosition(FALSE, boards[currentMove]);
\r
4914 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4915 boards[currentMove][toY][toX] = q;
\r
4917 PromotionPopup(hwnd);
\r
4918 } else { /* not a promotion */
\r
4919 if (appData.animate || appData.highlightLastMove) {
\r
4920 SetHighlights(fromX, fromY, toX, toY);
\r
4922 ClearHighlights();
\r
4924 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4925 fromX = fromY = -1;
\r
4926 if (appData.animate && !appData.highlightLastMove) {
\r
4927 ClearHighlights();
\r
4928 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4934 /* [HGM] it seemed that braces were missing here */
\r
4935 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4936 fromX = fromY = -1;
\r
4940 ClearHighlights();
\r
4941 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4943 /* First downclick, or restart on a square with same color piece */
\r
4944 if (!frozen && OKToStartUserMove(x, y)) {
\r
4947 dragInfo.lastpos = pt;
\r
4948 dragInfo.from.x = fromX;
\r
4949 dragInfo.from.y = fromY;
\r
4950 dragInfo.start = dragInfo.from;
\r
4951 SetCapture(hwndMain);
\r
4953 fromX = fromY = -1;
\r
4954 dragInfo.start.x = dragInfo.start.y = -1;
\r
4955 dragInfo.from = dragInfo.start;
\r
4956 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4960 case WM_LBUTTONUP:
\r
4962 if (fromX == -1) break;
\r
4963 if (x == fromX && y == fromY) {
\r
4964 dragInfo.from.x = dragInfo.from.y = -1;
\r
4965 /* Upclick on same square */
\r
4967 /* Clicked same square twice: abort click-click move */
\r
4968 fromX = fromY = -1;
\r
4970 ClearPremoveHighlights();
\r
4972 /* First square clicked: start click-click move */
\r
4973 SetHighlights(fromX, fromY, -1, -1);
\r
4975 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4976 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4977 /* Errant click; ignore */
\r
4980 /* Finish drag move. */
\r
4981 if (appData.debugMode) {
\r
4982 fprintf(debugFP, "release\n");
\r
4984 dragInfo.from.x = dragInfo.from.y = -1;
\r
4987 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4988 appData.animate = appData.animate && !appData.animateDragging;
\r
4989 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4990 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4991 fromX = fromY = -1;
\r
4992 ClearHighlights();
\r
4993 DrawPosition(FALSE, boards[currentMove]);
\r
4996 if(moveType != ImpossibleMove) {
\r
4997 /* [HGM] use move type to determine if move is promotion.
\r
4998 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4999 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5000 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5001 appData.alwaysPromoteToQueen)
\r
5002 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5004 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5005 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5006 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5007 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5008 // kludge to temporarily execute move on display, wthout promotng yet
\r
5009 promotionChoice = TRUE;
\r
5010 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5011 boards[currentMove][toY][toX] = p;
\r
5012 DrawPosition(FALSE, boards[currentMove]);
\r
5013 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5014 boards[currentMove][toY][toX] = q;
\r
5017 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5018 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5020 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5021 appData.animate = saveAnimate;
\r
5022 fromX = fromY = -1;
\r
5023 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5024 ClearHighlights();
\r
5026 if (appData.animate || appData.animateDragging ||
\r
5027 appData.highlightDragging || gotPremove) {
\r
5028 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5031 dragInfo.start.x = dragInfo.start.y = -1;
\r
5032 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5035 case WM_MOUSEMOVE:
\r
5036 if ((appData.animateDragging || appData.highlightDragging)
\r
5037 && (wParam & MK_LBUTTON)
\r
5038 && dragInfo.from.x >= 0)
\r
5040 BOOL full_repaint = FALSE;
\r
5042 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5043 if (appData.animateDragging) {
\r
5044 dragInfo.pos = pt;
\r
5046 if (appData.highlightDragging) {
\r
5047 SetHighlights(fromX, fromY, x, y);
\r
5048 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5049 full_repaint = TRUE;
\r
5053 DrawPosition( full_repaint, NULL);
\r
5055 dragInfo.lastpos = dragInfo.pos;
\r
5059 case WM_MOUSEWHEEL: // [DM]
\r
5060 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5061 /* Mouse Wheel is being rolled forward
\r
5062 * Play moves forward
\r
5064 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5065 if(lastDir == 1) ForwardEvent(); else lastDir = 1; // [HGM] suppress first event in each direction
\r
5066 /* Mouse Wheel is being rolled backward
\r
5067 * Play moves backward
\r
5069 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5070 if(lastDir == -1) BackwardEvent(); else lastDir = -1;
\r
5074 case WM_MBUTTONDOWN:
\r
5075 case WM_RBUTTONDOWN:
\r
5078 fromX = fromY = -1;
\r
5079 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5080 dragInfo.start.x = dragInfo.start.y = -1;
\r
5081 dragInfo.from = dragInfo.start;
\r
5082 dragInfo.lastpos = dragInfo.pos;
\r
5083 if (appData.highlightDragging) {
\r
5084 ClearHighlights();
\r
5087 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5088 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5089 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5090 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5091 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5094 DrawPosition(TRUE, NULL);
\r
5096 switch (gameMode) {
\r
5097 case EditPosition:
\r
5098 case IcsExamining:
\r
5099 if (x < 0 || y < 0) break;
\r
5102 if (message == WM_MBUTTONDOWN) {
\r
5103 buttonCount = 3; /* even if system didn't think so */
\r
5104 if (wParam & MK_SHIFT)
\r
5105 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5107 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5108 } else { /* message == WM_RBUTTONDOWN */
\r
5110 if (buttonCount == 3) {
\r
5111 if (wParam & MK_SHIFT)
\r
5112 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5114 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5116 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5119 /* Just have one menu, on the right button. Windows users don't
\r
5120 think to try the middle one, and sometimes other software steals
\r
5121 it, or it doesn't really exist. */
\r
5122 if(gameInfo.variant != VariantShogi)
\r
5123 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5125 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5129 case IcsPlayingWhite:
\r
5130 case IcsPlayingBlack:
\r
5132 case MachinePlaysWhite:
\r
5133 case MachinePlaysBlack:
\r
5134 if (appData.testLegality &&
\r
5135 gameInfo.variant != VariantBughouse &&
\r
5136 gameInfo.variant != VariantCrazyhouse) break;
\r
5137 if (x < 0 || y < 0) break;
\r
5140 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5141 SetupDropMenu(hmenu);
\r
5142 MenuPopup(hwnd, pt, hmenu, -1);
\r
5153 /* Preprocess messages for buttons in main window */
\r
5155 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5157 int id = GetWindowLong(hwnd, GWL_ID);
\r
5160 for (i=0; i<N_BUTTONS; i++) {
\r
5161 if (buttonDesc[i].id == id) break;
\r
5163 if (i == N_BUTTONS) return 0;
\r
5164 switch (message) {
\r
5169 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5170 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5177 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5180 if (appData.icsActive) {
\r
5181 if (GetKeyState(VK_SHIFT) < 0) {
\r
5183 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5184 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5188 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5189 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5196 if (appData.icsActive) {
\r
5197 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5198 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5200 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5202 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5203 PopUpMoveDialog((char)wParam);
\r
5209 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5212 /* Process messages for Promotion dialog box */
\r
5214 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5218 switch (message) {
\r
5219 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5220 /* Center the dialog over the application window */
\r
5221 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5222 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5223 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5224 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5225 SW_SHOW : SW_HIDE);
\r
5226 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5227 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5228 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5229 PieceToChar(WhiteAngel) != '~' ||
\r
5230 PieceToChar(BlackAngel) >= 'A' &&
\r
5231 PieceToChar(BlackAngel) != '~' ) ?
\r
5232 SW_SHOW : SW_HIDE);
\r
5233 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5234 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5235 PieceToChar(WhiteMarshall) != '~' ||
\r
5236 PieceToChar(BlackMarshall) >= 'A' &&
\r
5237 PieceToChar(BlackMarshall) != '~' ) ?
\r
5238 SW_SHOW : SW_HIDE);
\r
5239 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5240 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5241 gameInfo.variant != VariantShogi ?
\r
5242 SW_SHOW : SW_HIDE);
\r
5243 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5244 gameInfo.variant != VariantShogi ?
\r
5245 SW_SHOW : SW_HIDE);
\r
5246 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5247 gameInfo.variant == VariantShogi ?
\r
5248 SW_SHOW : SW_HIDE);
\r
5249 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5250 gameInfo.variant == VariantShogi ?
\r
5251 SW_SHOW : SW_HIDE);
\r
5252 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5253 gameInfo.variant == VariantSuper ?
\r
5254 SW_SHOW : SW_HIDE);
\r
5257 case WM_COMMAND: /* message: received a command */
\r
5258 switch (LOWORD(wParam)) {
\r
5260 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5261 ClearHighlights();
\r
5262 DrawPosition(FALSE, NULL);
\r
5265 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5268 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5271 promoChar = PieceToChar(BlackRook);
\r
5274 promoChar = PieceToChar(BlackBishop);
\r
5276 case PB_Chancellor:
\r
5277 promoChar = PieceToChar(BlackMarshall);
\r
5279 case PB_Archbishop:
\r
5280 promoChar = PieceToChar(BlackAngel);
\r
5283 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5288 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5289 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5290 only show the popup when we are already sure the move is valid or
\r
5291 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5292 will figure out it is a promotion from the promoChar. */
\r
5293 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5294 if (!appData.highlightLastMove) {
\r
5295 ClearHighlights();
\r
5296 DrawPosition(FALSE, NULL);
\r
5303 /* Pop up promotion dialog */
\r
5305 PromotionPopup(HWND hwnd)
\r
5309 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5310 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5311 hwnd, (DLGPROC)lpProc);
\r
5312 FreeProcInstance(lpProc);
\r
5315 /* Toggle ShowThinking */
\r
5317 ToggleShowThinking()
\r
5319 appData.showThinking = !appData.showThinking;
\r
5320 ShowThinkingEvent();
\r
5324 LoadGameDialog(HWND hwnd, char* title)
\r
5328 char fileTitle[MSG_SIZ];
\r
5329 f = OpenFileDialog(hwnd, "rb", "",
\r
5330 appData.oldSaveStyle ? "gam" : "pgn",
\r
5332 title, &number, fileTitle, NULL);
\r
5334 cmailMsgLoaded = FALSE;
\r
5335 if (number == 0) {
\r
5336 int error = GameListBuild(f);
\r
5338 DisplayError("Cannot build game list", error);
\r
5339 } else if (!ListEmpty(&gameList) &&
\r
5340 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5341 GameListPopUp(f, fileTitle);
\r
5344 GameListDestroy();
\r
5347 LoadGame(f, number, fileTitle, FALSE);
\r
5352 ChangedConsoleFont()
\r
5355 CHARRANGE tmpsel, sel;
\r
5356 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5357 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5358 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5361 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5362 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5363 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5364 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5365 * size. This was undocumented in the version of MSVC++ that I had
\r
5366 * when I wrote the code, but is apparently documented now.
\r
5368 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5369 cfmt.bCharSet = f->lf.lfCharSet;
\r
5370 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5371 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5372 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5373 /* Why are the following seemingly needed too? */
\r
5374 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5375 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5376 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5378 tmpsel.cpMax = -1; /*999999?*/
\r
5379 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5380 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5381 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5382 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5384 paraf.cbSize = sizeof(paraf);
\r
5385 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5386 paraf.dxStartIndent = 0;
\r
5387 paraf.dxOffset = WRAP_INDENT;
\r
5388 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5389 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5392 /*---------------------------------------------------------------------------*\
\r
5394 * Window Proc for main window
\r
5396 \*---------------------------------------------------------------------------*/
\r
5398 /* Process messages for main window, etc. */
\r
5400 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5403 int wmId, wmEvent;
\r
5407 char fileTitle[MSG_SIZ];
\r
5408 char buf[MSG_SIZ];
\r
5409 static SnapData sd;
\r
5411 switch (message) {
\r
5413 case WM_PAINT: /* message: repaint portion of window */
\r
5417 case WM_ERASEBKGND:
\r
5418 if (IsIconic(hwnd)) {
\r
5419 /* Cheat; change the message */
\r
5420 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5422 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5426 case WM_LBUTTONDOWN:
\r
5427 case WM_MBUTTONDOWN:
\r
5428 case WM_RBUTTONDOWN:
\r
5429 case WM_LBUTTONUP:
\r
5430 case WM_MBUTTONUP:
\r
5431 case WM_RBUTTONUP:
\r
5432 case WM_MOUSEMOVE:
\r
5433 case WM_MOUSEWHEEL:
\r
5434 MouseEvent(hwnd, message, wParam, lParam);
\r
5439 if (appData.icsActive) {
\r
5440 if (wParam == '\t') {
\r
5441 if (GetKeyState(VK_SHIFT) < 0) {
\r
5443 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5444 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5448 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5449 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5453 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5454 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5456 SendMessage(h, message, wParam, lParam);
\r
5458 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5459 PopUpMoveDialog((char)wParam);
\r
5463 case WM_PALETTECHANGED:
\r
5464 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5466 HDC hdc = GetDC(hwndMain);
\r
5467 SelectPalette(hdc, hPal, TRUE);
\r
5468 nnew = RealizePalette(hdc);
\r
5470 paletteChanged = TRUE;
\r
5472 UpdateColors(hdc);
\r
5474 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5477 ReleaseDC(hwnd, hdc);
\r
5481 case WM_QUERYNEWPALETTE:
\r
5482 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5484 HDC hdc = GetDC(hwndMain);
\r
5485 paletteChanged = FALSE;
\r
5486 SelectPalette(hdc, hPal, FALSE);
\r
5487 nnew = RealizePalette(hdc);
\r
5489 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5491 ReleaseDC(hwnd, hdc);
\r
5496 case WM_COMMAND: /* message: command from application menu */
\r
5497 wmId = LOWORD(wParam);
\r
5498 wmEvent = HIWORD(wParam);
\r
5503 AnalysisPopDown();
\r
5506 case IDM_NewGameFRC:
\r
5507 if( NewGameFRC() == 0 ) {
\r
5509 AnalysisPopDown();
\r
5513 case IDM_NewVariant:
\r
5514 NewVariantPopup(hwnd);
\r
5517 case IDM_LoadGame:
\r
5518 LoadGameDialog(hwnd, "Load Game from File");
\r
5521 case IDM_LoadNextGame:
\r
5525 case IDM_LoadPrevGame:
\r
5529 case IDM_ReloadGame:
\r
5533 case IDM_LoadPosition:
\r
5534 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5535 Reset(FALSE, TRUE);
\r
5538 f = OpenFileDialog(hwnd, "rb", "",
\r
5539 appData.oldSaveStyle ? "pos" : "fen",
\r
5541 "Load Position from File", &number, fileTitle, NULL);
\r
5543 LoadPosition(f, number, fileTitle);
\r
5547 case IDM_LoadNextPosition:
\r
5548 ReloadPosition(1);
\r
5551 case IDM_LoadPrevPosition:
\r
5552 ReloadPosition(-1);
\r
5555 case IDM_ReloadPosition:
\r
5556 ReloadPosition(0);
\r
5559 case IDM_SaveGame:
\r
5560 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5561 f = OpenFileDialog(hwnd, "a", defName,
\r
5562 appData.oldSaveStyle ? "gam" : "pgn",
\r
5564 "Save Game to File", NULL, fileTitle, NULL);
\r
5566 SaveGame(f, 0, "");
\r
5570 case IDM_SavePosition:
\r
5571 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5572 f = OpenFileDialog(hwnd, "a", defName,
\r
5573 appData.oldSaveStyle ? "pos" : "fen",
\r
5575 "Save Position to File", NULL, fileTitle, NULL);
\r
5577 SavePosition(f, 0, "");
\r
5581 case IDM_SaveDiagram:
\r
5582 defName = "diagram";
\r
5583 f = OpenFileDialog(hwnd, "wb", defName,
\r
5586 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5592 case IDM_CopyGame:
\r
5593 CopyGameToClipboard();
\r
5596 case IDM_PasteGame:
\r
5597 PasteGameFromClipboard();
\r
5600 case IDM_CopyGameListToClipboard:
\r
5601 CopyGameListToClipboard();
\r
5604 /* [AS] Autodetect FEN or PGN data */
\r
5605 case IDM_PasteAny:
\r
5606 PasteGameOrFENFromClipboard();
\r
5609 /* [AS] Move history */
\r
5610 case IDM_ShowMoveHistory:
\r
5611 if( MoveHistoryIsUp() ) {
\r
5612 MoveHistoryPopDown();
\r
5615 MoveHistoryPopUp();
\r
5619 /* [AS] Eval graph */
\r
5620 case IDM_ShowEvalGraph:
\r
5621 if( EvalGraphIsUp() ) {
\r
5622 EvalGraphPopDown();
\r
5629 /* [AS] Engine output */
\r
5630 case IDM_ShowEngineOutput:
\r
5631 if( EngineOutputIsUp() ) {
\r
5632 EngineOutputPopDown();
\r
5635 EngineOutputPopUp();
\r
5639 /* [AS] User adjudication */
\r
5640 case IDM_UserAdjudication_White:
\r
5641 UserAdjudicationEvent( +1 );
\r
5644 case IDM_UserAdjudication_Black:
\r
5645 UserAdjudicationEvent( -1 );
\r
5648 case IDM_UserAdjudication_Draw:
\r
5649 UserAdjudicationEvent( 0 );
\r
5652 /* [AS] Game list options dialog */
\r
5653 case IDM_GameListOptions:
\r
5654 GameListOptions();
\r
5657 case IDM_CopyPosition:
\r
5658 CopyFENToClipboard();
\r
5661 case IDM_PastePosition:
\r
5662 PasteFENFromClipboard();
\r
5665 case IDM_MailMove:
\r
5669 case IDM_ReloadCMailMsg:
\r
5670 Reset(TRUE, TRUE);
\r
5671 ReloadCmailMsgEvent(FALSE);
\r
5674 case IDM_Minimize:
\r
5675 ShowWindow(hwnd, SW_MINIMIZE);
\r
5682 case IDM_MachineWhite:
\r
5683 MachineWhiteEvent();
\r
5685 * refresh the tags dialog only if it's visible
\r
5687 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5689 tags = PGNTags(&gameInfo);
\r
5690 TagsPopUp(tags, CmailMsg());
\r
5695 case IDM_MachineBlack:
\r
5696 MachineBlackEvent();
\r
5698 * refresh the tags dialog only if it's visible
\r
5700 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5702 tags = PGNTags(&gameInfo);
\r
5703 TagsPopUp(tags, CmailMsg());
\r
5708 case IDM_TwoMachines:
\r
5709 TwoMachinesEvent();
\r
5711 * refresh the tags dialog only if it's visible
\r
5713 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5715 tags = PGNTags(&gameInfo);
\r
5716 TagsPopUp(tags, CmailMsg());
\r
5721 case IDM_AnalysisMode:
\r
5722 if (!first.analysisSupport) {
\r
5723 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5724 DisplayError(buf, 0);
\r
5726 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5727 if (appData.icsActive) {
\r
5728 if (gameMode != IcsObserving) {
\r
5729 sprintf(buf, "You are not observing a game");
\r
5730 DisplayError(buf, 0);
\r
5731 /* secure check */
\r
5732 if (appData.icsEngineAnalyze) {
\r
5733 if (appData.debugMode)
\r
5734 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5735 ExitAnalyzeMode();
\r
5741 /* if enable, user want disable icsEngineAnalyze */
\r
5742 if (appData.icsEngineAnalyze) {
\r
5743 ExitAnalyzeMode();
\r
5747 appData.icsEngineAnalyze = TRUE;
\r
5748 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5751 if (!appData.showThinking) ToggleShowThinking();
\r
5752 AnalyzeModeEvent();
\r
5756 case IDM_AnalyzeFile:
\r
5757 if (!first.analysisSupport) {
\r
5758 char buf[MSG_SIZ];
\r
5759 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5760 DisplayError(buf, 0);
\r
5762 if (!appData.showThinking) ToggleShowThinking();
\r
5763 AnalyzeFileEvent();
\r
5764 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5765 AnalysisPeriodicEvent(1);
\r
5769 case IDM_IcsClient:
\r
5773 case IDM_EditGame:
\r
5777 case IDM_EditPosition:
\r
5778 EditPositionEvent();
\r
5781 case IDM_Training:
\r
5785 case IDM_ShowGameList:
\r
5786 ShowGameListProc();
\r
5789 case IDM_EditTags:
\r
5793 case IDM_EditComment:
\r
5794 if (commentDialogUp && editComment) {
\r
5797 EditCommentEvent();
\r
5817 case IDM_CallFlag:
\r
5837 case IDM_StopObserving:
\r
5838 StopObservingEvent();
\r
5841 case IDM_StopExamining:
\r
5842 StopExaminingEvent();
\r
5845 case IDM_TypeInMove:
\r
5846 PopUpMoveDialog('\000');
\r
5849 case IDM_TypeInName:
\r
5850 PopUpNameDialog('\000');
\r
5853 case IDM_Backward:
\r
5855 SetFocus(hwndMain);
\r
5860 SetFocus(hwndMain);
\r
5865 SetFocus(hwndMain);
\r
5870 SetFocus(hwndMain);
\r
5877 case IDM_TruncateGame:
\r
5878 TruncateGameEvent();
\r
5885 case IDM_RetractMove:
\r
5886 RetractMoveEvent();
\r
5889 case IDM_FlipView:
\r
5890 flipView = !flipView;
\r
5891 DrawPosition(FALSE, NULL);
\r
5894 case IDM_FlipClock:
\r
5895 flipClock = !flipClock;
\r
5896 DisplayBothClocks();
\r
5899 case IDM_GeneralOptions:
\r
5900 GeneralOptionsPopup(hwnd);
\r
5901 DrawPosition(TRUE, NULL);
\r
5904 case IDM_BoardOptions:
\r
5905 BoardOptionsPopup(hwnd);
\r
5908 case IDM_EnginePlayOptions:
\r
5909 EnginePlayOptionsPopup(hwnd);
\r
5912 case IDM_OptionsUCI:
\r
5913 UciOptionsPopup(hwnd);
\r
5916 case IDM_IcsOptions:
\r
5917 IcsOptionsPopup(hwnd);
\r
5921 FontsOptionsPopup(hwnd);
\r
5925 SoundOptionsPopup(hwnd);
\r
5928 case IDM_CommPort:
\r
5929 CommPortOptionsPopup(hwnd);
\r
5932 case IDM_LoadOptions:
\r
5933 LoadOptionsPopup(hwnd);
\r
5936 case IDM_SaveOptions:
\r
5937 SaveOptionsPopup(hwnd);
\r
5940 case IDM_TimeControl:
\r
5941 TimeControlOptionsPopup(hwnd);
\r
5944 case IDM_SaveSettings:
\r
5945 SaveSettings(settingsFileName);
\r
5948 case IDM_SaveSettingsOnExit:
\r
5949 saveSettingsOnExit = !saveSettingsOnExit;
\r
5950 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5951 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5952 MF_CHECKED : MF_UNCHECKED));
\r
5963 case IDM_AboutGame:
\r
5968 appData.debugMode = !appData.debugMode;
\r
5969 if (appData.debugMode) {
\r
5970 char dir[MSG_SIZ];
\r
5971 GetCurrentDirectory(MSG_SIZ, dir);
\r
5972 SetCurrentDirectory(installDir);
\r
5973 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5974 SetCurrentDirectory(dir);
\r
5975 setbuf(debugFP, NULL);
\r
5982 case IDM_HELPCONTENTS:
\r
5983 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5984 MessageBox (GetFocus(),
\r
5985 "Unable to activate help",
\r
5986 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5990 case IDM_HELPSEARCH:
\r
5991 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5992 MessageBox (GetFocus(),
\r
5993 "Unable to activate help",
\r
5994 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5998 case IDM_HELPHELP:
\r
5999 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6000 MessageBox (GetFocus(),
\r
6001 "Unable to activate help",
\r
6002 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6007 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6009 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6010 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6011 FreeProcInstance(lpProc);
\r
6014 case IDM_DirectCommand1:
\r
6015 AskQuestionEvent("Direct Command",
\r
6016 "Send to chess program:", "", "1");
\r
6018 case IDM_DirectCommand2:
\r
6019 AskQuestionEvent("Direct Command",
\r
6020 "Send to second chess program:", "", "2");
\r
6023 case EP_WhitePawn:
\r
6024 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6025 fromX = fromY = -1;
\r
6028 case EP_WhiteKnight:
\r
6029 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6030 fromX = fromY = -1;
\r
6033 case EP_WhiteBishop:
\r
6034 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6035 fromX = fromY = -1;
\r
6038 case EP_WhiteRook:
\r
6039 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6040 fromX = fromY = -1;
\r
6043 case EP_WhiteQueen:
\r
6044 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6045 fromX = fromY = -1;
\r
6048 case EP_WhiteFerz:
\r
6049 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6050 fromX = fromY = -1;
\r
6053 case EP_WhiteWazir:
\r
6054 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6055 fromX = fromY = -1;
\r
6058 case EP_WhiteAlfil:
\r
6059 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6060 fromX = fromY = -1;
\r
6063 case EP_WhiteCannon:
\r
6064 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6065 fromX = fromY = -1;
\r
6068 case EP_WhiteCardinal:
\r
6069 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6070 fromX = fromY = -1;
\r
6073 case EP_WhiteMarshall:
\r
6074 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6075 fromX = fromY = -1;
\r
6078 case EP_WhiteKing:
\r
6079 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6080 fromX = fromY = -1;
\r
6083 case EP_BlackPawn:
\r
6084 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6085 fromX = fromY = -1;
\r
6088 case EP_BlackKnight:
\r
6089 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6090 fromX = fromY = -1;
\r
6093 case EP_BlackBishop:
\r
6094 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6095 fromX = fromY = -1;
\r
6098 case EP_BlackRook:
\r
6099 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6100 fromX = fromY = -1;
\r
6103 case EP_BlackQueen:
\r
6104 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6105 fromX = fromY = -1;
\r
6108 case EP_BlackFerz:
\r
6109 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6110 fromX = fromY = -1;
\r
6113 case EP_BlackWazir:
\r
6114 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6115 fromX = fromY = -1;
\r
6118 case EP_BlackAlfil:
\r
6119 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6120 fromX = fromY = -1;
\r
6123 case EP_BlackCannon:
\r
6124 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6125 fromX = fromY = -1;
\r
6128 case EP_BlackCardinal:
\r
6129 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6130 fromX = fromY = -1;
\r
6133 case EP_BlackMarshall:
\r
6134 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6135 fromX = fromY = -1;
\r
6138 case EP_BlackKing:
\r
6139 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6140 fromX = fromY = -1;
\r
6143 case EP_EmptySquare:
\r
6144 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6145 fromX = fromY = -1;
\r
6148 case EP_ClearBoard:
\r
6149 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6150 fromX = fromY = -1;
\r
6154 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6155 fromX = fromY = -1;
\r
6159 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6160 fromX = fromY = -1;
\r
6164 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6165 fromX = fromY = -1;
\r
6169 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6170 fromX = fromY = -1;
\r
6174 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6175 fromX = fromY = -1;
\r
6179 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6180 fromX = fromY = -1;
\r
6184 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6185 fromX = fromY = -1;
\r
6189 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6190 fromX = fromY = -1;
\r
6194 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6195 fromX = fromY = -1;
\r
6199 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6205 case CLOCK_TIMER_ID:
\r
6206 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6207 clockTimerEvent = 0;
\r
6208 DecrementClocks(); /* call into back end */
\r
6210 case LOAD_GAME_TIMER_ID:
\r
6211 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6212 loadGameTimerEvent = 0;
\r
6213 AutoPlayGameLoop(); /* call into back end */
\r
6215 case ANALYSIS_TIMER_ID:
\r
6216 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6217 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6218 AnalysisPeriodicEvent(0);
\r
6220 KillTimer(hwnd, analysisTimerEvent);
\r
6221 analysisTimerEvent = 0;
\r
6224 case DELAYED_TIMER_ID:
\r
6225 KillTimer(hwnd, delayedTimerEvent);
\r
6226 delayedTimerEvent = 0;
\r
6227 delayedTimerCallback();
\r
6232 case WM_USER_Input:
\r
6233 InputEvent(hwnd, message, wParam, lParam);
\r
6236 /* [AS] Also move "attached" child windows */
\r
6237 case WM_WINDOWPOSCHANGING:
\r
6238 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6239 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6241 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6242 /* Window is moving */
\r
6245 GetWindowRect( hwnd, &rcMain );
\r
6247 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6248 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6249 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6254 /* [AS] Snapping */
\r
6255 case WM_ENTERSIZEMOVE:
\r
6256 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6257 if (hwnd == hwndMain) {
\r
6258 doingSizing = TRUE;
\r
6261 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6265 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6266 if (hwnd == hwndMain) {
\r
6267 lastSizing = wParam;
\r
6272 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6273 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6275 case WM_EXITSIZEMOVE:
\r
6276 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6277 if (hwnd == hwndMain) {
\r
6279 doingSizing = FALSE;
\r
6280 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6281 GetClientRect(hwnd, &client);
\r
6282 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6284 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6286 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6289 case WM_DESTROY: /* message: window being destroyed */
\r
6290 PostQuitMessage(0);
\r
6294 if (hwnd == hwndMain) {
\r
6299 default: /* Passes it on if unprocessed */
\r
6300 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6305 /*---------------------------------------------------------------------------*\
\r
6307 * Misc utility routines
\r
6309 \*---------------------------------------------------------------------------*/
\r
6312 * Decent random number generator, at least not as bad as Windows
\r
6313 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6315 unsigned int randstate;
\r
6320 randstate = randstate * 1664525 + 1013904223;
\r
6321 return (int) randstate & 0x7fffffff;
\r
6325 mysrandom(unsigned int seed)
\r
6332 * returns TRUE if user selects a different color, FALSE otherwise
\r
6336 ChangeColor(HWND hwnd, COLORREF *which)
\r
6338 static BOOL firstTime = TRUE;
\r
6339 static DWORD customColors[16];
\r
6341 COLORREF newcolor;
\r
6346 /* Make initial colors in use available as custom colors */
\r
6347 /* Should we put the compiled-in defaults here instead? */
\r
6349 customColors[i++] = lightSquareColor & 0xffffff;
\r
6350 customColors[i++] = darkSquareColor & 0xffffff;
\r
6351 customColors[i++] = whitePieceColor & 0xffffff;
\r
6352 customColors[i++] = blackPieceColor & 0xffffff;
\r
6353 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6354 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6356 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6357 customColors[i++] = textAttribs[ccl].color;
\r
6359 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6360 firstTime = FALSE;
\r
6363 cc.lStructSize = sizeof(cc);
\r
6364 cc.hwndOwner = hwnd;
\r
6365 cc.hInstance = NULL;
\r
6366 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6367 cc.lpCustColors = (LPDWORD) customColors;
\r
6368 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6370 if (!ChooseColor(&cc)) return FALSE;
\r
6372 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6373 if (newcolor == *which) return FALSE;
\r
6374 *which = newcolor;
\r
6378 InitDrawingColors();
\r
6379 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6384 MyLoadSound(MySound *ms)
\r
6390 if (ms->data) free(ms->data);
\r
6393 switch (ms->name[0]) {
\r
6399 /* System sound from Control Panel. Don't preload here. */
\r
6403 if (ms->name[1] == NULLCHAR) {
\r
6404 /* "!" alone = silence */
\r
6407 /* Builtin wave resource. Error if not found. */
\r
6408 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6409 if (h == NULL) break;
\r
6410 ms->data = (void *)LoadResource(hInst, h);
\r
6411 if (h == NULL) break;
\r
6416 /* .wav file. Error if not found. */
\r
6417 f = fopen(ms->name, "rb");
\r
6418 if (f == NULL) break;
\r
6419 if (fstat(fileno(f), &st) < 0) break;
\r
6420 ms->data = malloc(st.st_size);
\r
6421 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6427 char buf[MSG_SIZ];
\r
6428 sprintf(buf, "Error loading sound %s", ms->name);
\r
6429 DisplayError(buf, GetLastError());
\r
6435 MyPlaySound(MySound *ms)
\r
6437 BOOLEAN ok = FALSE;
\r
6438 switch (ms->name[0]) {
\r
6444 /* System sound from Control Panel (deprecated feature).
\r
6445 "$" alone or an unset sound name gets default beep (still in use). */
\r
6446 if (ms->name[1]) {
\r
6447 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6449 if (!ok) ok = MessageBeep(MB_OK);
\r
6452 /* Builtin wave resource, or "!" alone for silence */
\r
6453 if (ms->name[1]) {
\r
6454 if (ms->data == NULL) return FALSE;
\r
6455 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6461 /* .wav file. Error if not found. */
\r
6462 if (ms->data == NULL) return FALSE;
\r
6463 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6466 /* Don't print an error: this can happen innocently if the sound driver
\r
6467 is busy; for instance, if another instance of WinBoard is playing
\r
6468 a sound at about the same time. */
\r
6471 char buf[MSG_SIZ];
\r
6472 sprintf(buf, "Error playing sound %s", ms->name);
\r
6473 DisplayError(buf, GetLastError());
\r
6481 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6484 OPENFILENAME *ofn;
\r
6485 static UINT *number; /* gross that this is static */
\r
6487 switch (message) {
\r
6488 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6489 /* Center the dialog over the application window */
\r
6490 ofn = (OPENFILENAME *) lParam;
\r
6491 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6492 number = (UINT *) ofn->lCustData;
\r
6493 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6497 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6498 return FALSE; /* Allow for further processing */
\r
6501 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6502 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6504 return FALSE; /* Allow for further processing */
\r
6510 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6512 static UINT *number;
\r
6513 OPENFILENAME *ofname;
\r
6516 case WM_INITDIALOG:
\r
6517 ofname = (OPENFILENAME *)lParam;
\r
6518 number = (UINT *)(ofname->lCustData);
\r
6521 ofnot = (OFNOTIFY *)lParam;
\r
6522 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6523 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6532 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6533 char *nameFilt, char *dlgTitle, UINT *number,
\r
6534 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6536 OPENFILENAME openFileName;
\r
6537 char buf1[MSG_SIZ];
\r
6540 if (fileName == NULL) fileName = buf1;
\r
6541 if (defName == NULL) {
\r
6542 strcpy(fileName, "*.");
\r
6543 strcat(fileName, defExt);
\r
6545 strcpy(fileName, defName);
\r
6547 if (fileTitle) strcpy(fileTitle, "");
\r
6548 if (number) *number = 0;
\r
6550 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6551 openFileName.hwndOwner = hwnd;
\r
6552 openFileName.hInstance = (HANDLE) hInst;
\r
6553 openFileName.lpstrFilter = nameFilt;
\r
6554 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6555 openFileName.nMaxCustFilter = 0L;
\r
6556 openFileName.nFilterIndex = 1L;
\r
6557 openFileName.lpstrFile = fileName;
\r
6558 openFileName.nMaxFile = MSG_SIZ;
\r
6559 openFileName.lpstrFileTitle = fileTitle;
\r
6560 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6561 openFileName.lpstrInitialDir = NULL;
\r
6562 openFileName.lpstrTitle = dlgTitle;
\r
6563 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6564 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6565 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6566 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6567 openFileName.nFileOffset = 0;
\r
6568 openFileName.nFileExtension = 0;
\r
6569 openFileName.lpstrDefExt = defExt;
\r
6570 openFileName.lCustData = (LONG) number;
\r
6571 openFileName.lpfnHook = oldDialog ?
\r
6572 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6573 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6575 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6576 GetOpenFileName(&openFileName)) {
\r
6577 /* open the file */
\r
6578 f = fopen(openFileName.lpstrFile, write);
\r
6580 MessageBox(hwnd, "File open failed", NULL,
\r
6581 MB_OK|MB_ICONEXCLAMATION);
\r
6585 int err = CommDlgExtendedError();
\r
6586 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6595 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6597 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6600 * Get the first pop-up menu in the menu template. This is the
\r
6601 * menu that TrackPopupMenu displays.
\r
6603 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6605 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6608 * TrackPopup uses screen coordinates, so convert the
\r
6609 * coordinates of the mouse click to screen coordinates.
\r
6611 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6613 /* Draw and track the floating pop-up menu. */
\r
6614 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6615 pt.x, pt.y, 0, hwnd, NULL);
\r
6617 /* Destroy the menu.*/
\r
6618 DestroyMenu(hmenu);
\r
6623 int sizeX, sizeY, newSizeX, newSizeY;
\r
6625 } ResizeEditPlusButtonsClosure;
\r
6628 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6630 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6634 if (hChild == cl->hText) return TRUE;
\r
6635 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6636 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6637 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6638 ScreenToClient(cl->hDlg, &pt);
\r
6639 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6640 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6644 /* Resize a dialog that has a (rich) edit field filling most of
\r
6645 the top, with a row of buttons below */
\r
6647 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6650 int newTextHeight, newTextWidth;
\r
6651 ResizeEditPlusButtonsClosure cl;
\r
6653 /*if (IsIconic(hDlg)) return;*/
\r
6654 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6656 cl.hdwp = BeginDeferWindowPos(8);
\r
6658 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6659 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6660 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6661 if (newTextHeight < 0) {
\r
6662 newSizeY += -newTextHeight;
\r
6663 newTextHeight = 0;
\r
6665 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6666 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6672 cl.newSizeX = newSizeX;
\r
6673 cl.newSizeY = newSizeY;
\r
6674 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6676 EndDeferWindowPos(cl.hdwp);
\r
6679 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6681 RECT rChild, rParent;
\r
6682 int wChild, hChild, wParent, hParent;
\r
6683 int wScreen, hScreen, xNew, yNew;
\r
6686 /* Get the Height and Width of the child window */
\r
6687 GetWindowRect (hwndChild, &rChild);
\r
6688 wChild = rChild.right - rChild.left;
\r
6689 hChild = rChild.bottom - rChild.top;
\r
6691 /* Get the Height and Width of the parent window */
\r
6692 GetWindowRect (hwndParent, &rParent);
\r
6693 wParent = rParent.right - rParent.left;
\r
6694 hParent = rParent.bottom - rParent.top;
\r
6696 /* Get the display limits */
\r
6697 hdc = GetDC (hwndChild);
\r
6698 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6699 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6700 ReleaseDC(hwndChild, hdc);
\r
6702 /* Calculate new X position, then adjust for screen */
\r
6703 xNew = rParent.left + ((wParent - wChild) /2);
\r
6706 } else if ((xNew+wChild) > wScreen) {
\r
6707 xNew = wScreen - wChild;
\r
6710 /* Calculate new Y position, then adjust for screen */
\r
6712 yNew = rParent.top + ((hParent - hChild) /2);
\r
6715 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6720 } else if ((yNew+hChild) > hScreen) {
\r
6721 yNew = hScreen - hChild;
\r
6724 /* Set it, and return */
\r
6725 return SetWindowPos (hwndChild, NULL,
\r
6726 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6729 /* Center one window over another */
\r
6730 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6732 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6735 /*---------------------------------------------------------------------------*\
\r
6737 * Startup Dialog functions
\r
6739 \*---------------------------------------------------------------------------*/
\r
6741 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6743 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6745 while (*cd != NULL) {
\r
6746 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6752 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6754 char buf1[ARG_MAX];
\r
6757 if (str[0] == '@') {
\r
6758 FILE* f = fopen(str + 1, "r");
\r
6760 DisplayFatalError(str + 1, errno, 2);
\r
6763 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6765 buf1[len] = NULLCHAR;
\r
6769 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6772 char buf[MSG_SIZ];
\r
6773 char *end = strchr(str, '\n');
\r
6774 if (end == NULL) return;
\r
6775 memcpy(buf, str, end - str);
\r
6776 buf[end - str] = NULLCHAR;
\r
6777 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6783 SetStartupDialogEnables(HWND hDlg)
\r
6785 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6786 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6787 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6788 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6789 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6790 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6791 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6792 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6793 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6794 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6795 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6796 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6797 IsDlgButtonChecked(hDlg, OPT_View));
\r
6801 QuoteForFilename(char *filename)
\r
6803 int dquote, space;
\r
6804 dquote = strchr(filename, '"') != NULL;
\r
6805 space = strchr(filename, ' ') != NULL;
\r
6806 if (dquote || space) {
\r
6818 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6820 char buf[MSG_SIZ];
\r
6823 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6824 q = QuoteForFilename(nthcp);
\r
6825 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6826 if (*nthdir != NULLCHAR) {
\r
6827 q = QuoteForFilename(nthdir);
\r
6828 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6830 if (*nthcp == NULLCHAR) {
\r
6831 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6832 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6833 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6834 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6839 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6841 char buf[MSG_SIZ];
\r
6845 switch (message) {
\r
6846 case WM_INITDIALOG:
\r
6847 /* Center the dialog */
\r
6848 CenterWindow (hDlg, GetDesktopWindow());
\r
6849 /* Initialize the dialog items */
\r
6850 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6851 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6852 firstChessProgramNames);
\r
6853 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6854 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6855 secondChessProgramNames);
\r
6856 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6857 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6858 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6859 if (*appData.icsHelper != NULLCHAR) {
\r
6860 char *q = QuoteForFilename(appData.icsHelper);
\r
6861 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6863 if (*appData.icsHost == NULLCHAR) {
\r
6864 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6865 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6866 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6867 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6868 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6871 if (appData.icsActive) {
\r
6872 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6874 else if (appData.noChessProgram) {
\r
6875 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6878 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6881 SetStartupDialogEnables(hDlg);
\r
6885 switch (LOWORD(wParam)) {
\r
6887 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6888 strcpy(buf, "/fcp=");
\r
6889 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6891 ParseArgs(StringGet, &p);
\r
6892 strcpy(buf, "/scp=");
\r
6893 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6895 ParseArgs(StringGet, &p);
\r
6896 appData.noChessProgram = FALSE;
\r
6897 appData.icsActive = FALSE;
\r
6898 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6899 strcpy(buf, "/ics /icshost=");
\r
6900 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6902 ParseArgs(StringGet, &p);
\r
6903 if (appData.zippyPlay) {
\r
6904 strcpy(buf, "/fcp=");
\r
6905 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6907 ParseArgs(StringGet, &p);
\r
6909 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6910 appData.noChessProgram = TRUE;
\r
6911 appData.icsActive = FALSE;
\r
6913 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6914 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6917 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6918 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6920 ParseArgs(StringGet, &p);
\r
6922 EndDialog(hDlg, TRUE);
\r
6929 case IDM_HELPCONTENTS:
\r
6930 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6931 MessageBox (GetFocus(),
\r
6932 "Unable to activate help",
\r
6933 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6938 SetStartupDialogEnables(hDlg);
\r
6946 /*---------------------------------------------------------------------------*\
\r
6948 * About box dialog functions
\r
6950 \*---------------------------------------------------------------------------*/
\r
6952 /* Process messages for "About" dialog box */
\r
6954 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6956 switch (message) {
\r
6957 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6958 /* Center the dialog over the application window */
\r
6959 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6960 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6963 case WM_COMMAND: /* message: received a command */
\r
6964 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6965 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6966 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6974 /*---------------------------------------------------------------------------*\
\r
6976 * Comment Dialog functions
\r
6978 \*---------------------------------------------------------------------------*/
\r
6981 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6983 static HANDLE hwndText = NULL;
\r
6984 int len, newSizeX, newSizeY, flags;
\r
6985 static int sizeX, sizeY;
\r
6990 switch (message) {
\r
6991 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6992 /* Initialize the dialog items */
\r
6993 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6994 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6995 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6996 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6997 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6998 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6999 SetWindowText(hDlg, commentTitle);
\r
7000 if (editComment) {
\r
7001 SetFocus(hwndText);
\r
7003 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7005 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7006 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7007 MAKELPARAM(FALSE, 0));
\r
7008 /* Size and position the dialog */
\r
7009 if (!commentDialog) {
\r
7010 commentDialog = hDlg;
\r
7011 flags = SWP_NOZORDER;
\r
7012 GetClientRect(hDlg, &rect);
\r
7013 sizeX = rect.right;
\r
7014 sizeY = rect.bottom;
\r
7015 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7016 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7017 WINDOWPLACEMENT wp;
\r
7018 EnsureOnScreen(&commentX, &commentY);
\r
7019 wp.length = sizeof(WINDOWPLACEMENT);
\r
7021 wp.showCmd = SW_SHOW;
\r
7022 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7023 wp.rcNormalPosition.left = commentX;
\r
7024 wp.rcNormalPosition.right = commentX + commentW;
\r
7025 wp.rcNormalPosition.top = commentY;
\r
7026 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7027 SetWindowPlacement(hDlg, &wp);
\r
7029 GetClientRect(hDlg, &rect);
\r
7030 newSizeX = rect.right;
\r
7031 newSizeY = rect.bottom;
\r
7032 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7033 newSizeX, newSizeY);
\r
7040 case WM_COMMAND: /* message: received a command */
\r
7041 switch (LOWORD(wParam)) {
\r
7043 if (editComment) {
\r
7045 /* Read changed options from the dialog box */
\r
7046 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7047 len = GetWindowTextLength(hwndText);
\r
7048 str = (char *) malloc(len + 1);
\r
7049 GetWindowText(hwndText, str, len + 1);
\r
7058 ReplaceComment(commentIndex, str);
\r
7065 case OPT_CancelComment:
\r
7069 case OPT_ClearComment:
\r
7070 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7073 case OPT_EditComment:
\r
7074 EditCommentEvent();
\r
7083 newSizeX = LOWORD(lParam);
\r
7084 newSizeY = HIWORD(lParam);
\r
7085 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7090 case WM_GETMINMAXINFO:
\r
7091 /* Prevent resizing window too small */
\r
7092 mmi = (MINMAXINFO *) lParam;
\r
7093 mmi->ptMinTrackSize.x = 100;
\r
7094 mmi->ptMinTrackSize.y = 100;
\r
7101 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7106 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7108 if (str == NULL) str = "";
\r
7109 p = (char *) malloc(2 * strlen(str) + 2);
\r
7112 if (*str == '\n') *q++ = '\r';
\r
7116 if (commentText != NULL) free(commentText);
\r
7118 commentIndex = index;
\r
7119 commentTitle = title;
\r
7121 editComment = edit;
\r
7123 if (commentDialog) {
\r
7124 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7125 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7127 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7128 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7129 hwndMain, (DLGPROC)lpProc);
\r
7130 FreeProcInstance(lpProc);
\r
7132 commentDialogUp = TRUE;
\r
7136 /*---------------------------------------------------------------------------*\
\r
7138 * Type-in move dialog functions
\r
7140 \*---------------------------------------------------------------------------*/
\r
7143 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7145 char move[MSG_SIZ];
\r
7147 ChessMove moveType;
\r
7148 int fromX, fromY, toX, toY;
\r
7151 switch (message) {
\r
7152 case WM_INITDIALOG:
\r
7153 move[0] = (char) lParam;
\r
7154 move[1] = NULLCHAR;
\r
7155 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7156 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7157 SetWindowText(hInput, move);
\r
7159 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7163 switch (LOWORD(wParam)) {
\r
7165 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7166 gameMode != Training) {
\r
7167 DisplayMoveError("Displayed move is not current");
\r
7169 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7170 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7171 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7172 if (gameMode != Training)
\r
7173 forwardMostMove = currentMove;
\r
7174 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7176 DisplayMoveError("Could not parse move");
\r
7179 EndDialog(hDlg, TRUE);
\r
7182 EndDialog(hDlg, FALSE);
\r
7193 PopUpMoveDialog(char firstchar)
\r
7197 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7198 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7199 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7200 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7201 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7202 gameMode == Training) {
\r
7203 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7204 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7205 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7206 FreeProcInstance(lpProc);
\r
7210 /*---------------------------------------------------------------------------*\
\r
7212 * Type-in name dialog functions
\r
7214 \*---------------------------------------------------------------------------*/
\r
7217 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7219 char move[MSG_SIZ];
\r
7222 switch (message) {
\r
7223 case WM_INITDIALOG:
\r
7224 move[0] = (char) lParam;
\r
7225 move[1] = NULLCHAR;
\r
7226 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7227 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7228 SetWindowText(hInput, move);
\r
7230 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7234 switch (LOWORD(wParam)) {
\r
7236 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7237 appData.userName = strdup(move);
\r
7239 EndDialog(hDlg, TRUE);
\r
7242 EndDialog(hDlg, FALSE);
\r
7253 PopUpNameDialog(char firstchar)
\r
7257 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7258 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7259 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7260 FreeProcInstance(lpProc);
\r
7263 /*---------------------------------------------------------------------------*\
\r
7267 \*---------------------------------------------------------------------------*/
\r
7269 /* Nonmodal error box */
\r
7270 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7271 WPARAM wParam, LPARAM lParam);
\r
7274 ErrorPopUp(char *title, char *content)
\r
7278 BOOLEAN modal = hwndMain == NULL;
\r
7296 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7297 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7300 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7302 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7303 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7304 hwndMain, (DLGPROC)lpProc);
\r
7305 FreeProcInstance(lpProc);
\r
7312 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7313 if (errorDialog == NULL) return;
\r
7314 DestroyWindow(errorDialog);
\r
7315 errorDialog = NULL;
\r
7319 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7324 switch (message) {
\r
7325 case WM_INITDIALOG:
\r
7326 GetWindowRect(hDlg, &rChild);
\r
7329 SetWindowPos(hDlg, NULL, rChild.left,
\r
7330 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7331 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7335 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7336 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7337 and it doesn't work when you resize the dialog.
\r
7338 For now, just give it a default position.
\r
7340 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7342 errorDialog = hDlg;
\r
7343 SetWindowText(hDlg, errorTitle);
\r
7344 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7345 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7349 switch (LOWORD(wParam)) {
\r
7352 if (errorDialog == hDlg) errorDialog = NULL;
\r
7353 DestroyWindow(hDlg);
\r
7365 HWND gothicDialog = NULL;
\r
7368 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7372 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7374 switch (message) {
\r
7375 case WM_INITDIALOG:
\r
7376 GetWindowRect(hDlg, &rChild);
\r
7378 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7382 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7383 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7384 and it doesn't work when you resize the dialog.
\r
7385 For now, just give it a default position.
\r
7387 gothicDialog = hDlg;
\r
7388 SetWindowText(hDlg, errorTitle);
\r
7389 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7390 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7394 switch (LOWORD(wParam)) {
\r
7397 if (errorDialog == hDlg) errorDialog = NULL;
\r
7398 DestroyWindow(hDlg);
\r
7410 GothicPopUp(char *title, VariantClass variant)
\r
7414 BOOLEAN modal = hwndMain == NULL;
\r
7415 static char *lastTitle;
\r
7417 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7418 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7420 if(lastTitle != title && gothicDialog != NULL) {
\r
7421 DestroyWindow(gothicDialog);
\r
7422 gothicDialog = NULL;
\r
7424 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7425 title = lastTitle;
\r
7426 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7427 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7428 hwndMain, (DLGPROC)lpProc);
\r
7429 FreeProcInstance(lpProc);
\r
7434 /*---------------------------------------------------------------------------*\
\r
7436 * Ics Interaction console functions
\r
7438 \*---------------------------------------------------------------------------*/
\r
7440 #define HISTORY_SIZE 64
\r
7441 static char *history[HISTORY_SIZE];
\r
7442 int histIn = 0, histP = 0;
\r
7445 SaveInHistory(char *cmd)
\r
7447 if (history[histIn] != NULL) {
\r
7448 free(history[histIn]);
\r
7449 history[histIn] = NULL;
\r
7451 if (*cmd == NULLCHAR) return;
\r
7452 history[histIn] = StrSave(cmd);
\r
7453 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7454 if (history[histIn] != NULL) {
\r
7455 free(history[histIn]);
\r
7456 history[histIn] = NULL;
\r
7462 PrevInHistory(char *cmd)
\r
7465 if (histP == histIn) {
\r
7466 if (history[histIn] != NULL) free(history[histIn]);
\r
7467 history[histIn] = StrSave(cmd);
\r
7469 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7470 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7472 return history[histP];
\r
7478 if (histP == histIn) return NULL;
\r
7479 histP = (histP + 1) % HISTORY_SIZE;
\r
7480 return history[histP];
\r
7487 BOOLEAN immediate;
\r
7488 } IcsTextMenuEntry;
\r
7489 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7490 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7493 ParseIcsTextMenu(char *icsTextMenuString)
\r
7496 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7497 char *p = icsTextMenuString;
\r
7498 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7501 if (e->command != NULL) {
\r
7503 e->command = NULL;
\r
7507 e = icsTextMenuEntry;
\r
7508 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7509 if (*p == ';' || *p == '\n') {
\r
7510 e->item = strdup("-");
\r
7511 e->command = NULL;
\r
7513 } else if (*p == '-') {
\r
7514 e->item = strdup("-");
\r
7515 e->command = NULL;
\r
7519 char *q, *r, *s, *t;
\r
7521 q = strchr(p, ',');
\r
7522 if (q == NULL) break;
\r
7524 r = strchr(q + 1, ',');
\r
7525 if (r == NULL) break;
\r
7527 s = strchr(r + 1, ',');
\r
7528 if (s == NULL) break;
\r
7531 t = strchr(s + 1, c);
\r
7534 t = strchr(s + 1, c);
\r
7536 if (t != NULL) *t = NULLCHAR;
\r
7537 e->item = strdup(p);
\r
7538 e->command = strdup(q + 1);
\r
7539 e->getname = *(r + 1) != '0';
\r
7540 e->immediate = *(s + 1) != '0';
\r
7544 if (t == NULL) break;
\r
7553 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7557 hmenu = LoadMenu(hInst, "TextMenu");
\r
7558 h = GetSubMenu(hmenu, 0);
\r
7560 if (strcmp(e->item, "-") == 0) {
\r
7561 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7563 if (e->item[0] == '|') {
\r
7564 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7565 IDM_CommandX + i, &e->item[1]);
\r
7567 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7576 WNDPROC consoleTextWindowProc;
\r
7579 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7581 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7582 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7586 SetWindowText(hInput, command);
\r
7588 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7590 sel.cpMin = 999999;
\r
7591 sel.cpMax = 999999;
\r
7592 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7597 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7598 if (sel.cpMin == sel.cpMax) {
\r
7599 /* Expand to surrounding word */
\r
7602 tr.chrg.cpMax = sel.cpMin;
\r
7603 tr.chrg.cpMin = --sel.cpMin;
\r
7604 if (sel.cpMin < 0) break;
\r
7605 tr.lpstrText = name;
\r
7606 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7607 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7611 tr.chrg.cpMin = sel.cpMax;
\r
7612 tr.chrg.cpMax = ++sel.cpMax;
\r
7613 tr.lpstrText = name;
\r
7614 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7615 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7618 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7619 MessageBeep(MB_ICONEXCLAMATION);
\r
7623 tr.lpstrText = name;
\r
7624 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7626 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7627 MessageBeep(MB_ICONEXCLAMATION);
\r
7630 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7633 sprintf(buf, "%s %s", command, name);
\r
7634 SetWindowText(hInput, buf);
\r
7635 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7637 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7638 SetWindowText(hInput, buf);
\r
7639 sel.cpMin = 999999;
\r
7640 sel.cpMax = 999999;
\r
7641 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7647 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7652 switch (message) {
\r
7654 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7657 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7660 sel.cpMin = 999999;
\r
7661 sel.cpMax = 999999;
\r
7662 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7663 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7668 if (wParam == '\t') {
\r
7669 if (GetKeyState(VK_SHIFT) < 0) {
\r
7671 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7672 if (buttonDesc[0].hwnd) {
\r
7673 SetFocus(buttonDesc[0].hwnd);
\r
7675 SetFocus(hwndMain);
\r
7679 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7682 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7684 SendMessage(hInput, message, wParam, lParam);
\r
7688 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7690 return SendMessage(hInput, message, wParam, lParam);
\r
7691 case WM_MBUTTONDOWN:
\r
7692 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7693 case WM_RBUTTONDOWN:
\r
7694 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7695 /* Move selection here if it was empty */
\r
7697 pt.x = LOWORD(lParam);
\r
7698 pt.y = HIWORD(lParam);
\r
7699 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7700 if (sel.cpMin == sel.cpMax) {
\r
7701 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7702 sel.cpMax = sel.cpMin;
\r
7703 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7705 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7708 case WM_RBUTTONUP:
\r
7709 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7710 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7711 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7714 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7715 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7716 if (sel.cpMin == sel.cpMax) {
\r
7717 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7718 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7720 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7721 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7723 pt.x = LOWORD(lParam);
\r
7724 pt.y = HIWORD(lParam);
\r
7725 MenuPopup(hwnd, pt, hmenu, -1);
\r
7729 switch (LOWORD(wParam)) {
\r
7730 case IDM_QuickPaste:
\r
7732 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7733 if (sel.cpMin == sel.cpMax) {
\r
7734 MessageBeep(MB_ICONEXCLAMATION);
\r
7737 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7738 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7739 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7744 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7747 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7750 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7754 int i = LOWORD(wParam) - IDM_CommandX;
\r
7755 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7756 icsTextMenuEntry[i].command != NULL) {
\r
7757 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7758 icsTextMenuEntry[i].getname,
\r
7759 icsTextMenuEntry[i].immediate);
\r
7767 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7770 WNDPROC consoleInputWindowProc;
\r
7773 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7775 char buf[MSG_SIZ];
\r
7777 static BOOL sendNextChar = FALSE;
\r
7778 static BOOL quoteNextChar = FALSE;
\r
7779 InputSource *is = consoleInputSource;
\r
7783 switch (message) {
\r
7785 if (!appData.localLineEditing || sendNextChar) {
\r
7786 is->buf[0] = (CHAR) wParam;
\r
7788 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7789 sendNextChar = FALSE;
\r
7792 if (quoteNextChar) {
\r
7793 buf[0] = (char) wParam;
\r
7794 buf[1] = NULLCHAR;
\r
7795 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7796 quoteNextChar = FALSE;
\r
7800 case '\r': /* Enter key */
\r
7801 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7802 if (consoleEcho) SaveInHistory(is->buf);
\r
7803 is->buf[is->count++] = '\n';
\r
7804 is->buf[is->count] = NULLCHAR;
\r
7805 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7806 if (consoleEcho) {
\r
7807 ConsoleOutput(is->buf, is->count, TRUE);
\r
7808 } else if (appData.localLineEditing) {
\r
7809 ConsoleOutput("\n", 1, TRUE);
\r
7812 case '\033': /* Escape key */
\r
7813 SetWindowText(hwnd, "");
\r
7814 cf.cbSize = sizeof(CHARFORMAT);
\r
7815 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7816 if (consoleEcho) {
\r
7817 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7819 cf.crTextColor = COLOR_ECHOOFF;
\r
7821 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7822 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7824 case '\t': /* Tab key */
\r
7825 if (GetKeyState(VK_SHIFT) < 0) {
\r
7827 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7830 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7831 if (buttonDesc[0].hwnd) {
\r
7832 SetFocus(buttonDesc[0].hwnd);
\r
7834 SetFocus(hwndMain);
\r
7838 case '\023': /* Ctrl+S */
\r
7839 sendNextChar = TRUE;
\r
7841 case '\021': /* Ctrl+Q */
\r
7842 quoteNextChar = TRUE;
\r
7851 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7852 p = PrevInHistory(buf);
\r
7854 SetWindowText(hwnd, p);
\r
7855 sel.cpMin = 999999;
\r
7856 sel.cpMax = 999999;
\r
7857 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7862 p = NextInHistory();
\r
7864 SetWindowText(hwnd, p);
\r
7865 sel.cpMin = 999999;
\r
7866 sel.cpMax = 999999;
\r
7867 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7873 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7877 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7881 case WM_MBUTTONDOWN:
\r
7882 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7883 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7885 case WM_RBUTTONUP:
\r
7886 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7887 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7888 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7892 hmenu = LoadMenu(hInst, "InputMenu");
\r
7893 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7894 if (sel.cpMin == sel.cpMax) {
\r
7895 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7896 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7898 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7899 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7901 pt.x = LOWORD(lParam);
\r
7902 pt.y = HIWORD(lParam);
\r
7903 MenuPopup(hwnd, pt, hmenu, -1);
\r
7907 switch (LOWORD(wParam)) {
\r
7909 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7911 case IDM_SelectAll:
\r
7913 sel.cpMax = -1; /*999999?*/
\r
7914 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7917 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7920 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7923 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7928 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7931 #define CO_MAX 100000
\r
7932 #define CO_TRIM 1000
\r
7935 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7937 static SnapData sd;
\r
7938 static HWND hText, hInput, hFocus;
\r
7939 InputSource *is = consoleInputSource;
\r
7941 static int sizeX, sizeY;
\r
7942 int newSizeX, newSizeY;
\r
7945 switch (message) {
\r
7946 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7947 hwndConsole = hDlg;
\r
7948 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7949 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7951 consoleTextWindowProc = (WNDPROC)
\r
7952 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7953 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7954 consoleInputWindowProc = (WNDPROC)
\r
7955 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7956 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7957 Colorize(ColorNormal, TRUE);
\r
7958 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7959 ChangedConsoleFont();
\r
7960 GetClientRect(hDlg, &rect);
\r
7961 sizeX = rect.right;
\r
7962 sizeY = rect.bottom;
\r
7963 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7964 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7965 WINDOWPLACEMENT wp;
\r
7966 EnsureOnScreen(&consoleX, &consoleY);
\r
7967 wp.length = sizeof(WINDOWPLACEMENT);
\r
7969 wp.showCmd = SW_SHOW;
\r
7970 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7971 wp.rcNormalPosition.left = consoleX;
\r
7972 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7973 wp.rcNormalPosition.top = consoleY;
\r
7974 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7975 SetWindowPlacement(hDlg, &wp);
\r
7978 // [HGM] Chessknight's change 2004-07-13
\r
7979 else { /* Determine Defaults */
\r
7980 WINDOWPLACEMENT wp;
\r
7981 consoleX = winWidth + 1;
\r
7982 consoleY = boardY;
\r
7983 consoleW = screenWidth - winWidth;
\r
7984 consoleH = winHeight;
\r
7985 EnsureOnScreen(&consoleX, &consoleY);
\r
7986 wp.length = sizeof(WINDOWPLACEMENT);
\r
7988 wp.showCmd = SW_SHOW;
\r
7989 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7990 wp.rcNormalPosition.left = consoleX;
\r
7991 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7992 wp.rcNormalPosition.top = consoleY;
\r
7993 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7994 SetWindowPlacement(hDlg, &wp);
\r
8009 if (IsIconic(hDlg)) break;
\r
8010 newSizeX = LOWORD(lParam);
\r
8011 newSizeY = HIWORD(lParam);
\r
8012 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8013 RECT rectText, rectInput;
\r
8015 int newTextHeight, newTextWidth;
\r
8016 GetWindowRect(hText, &rectText);
\r
8017 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8018 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8019 if (newTextHeight < 0) {
\r
8020 newSizeY += -newTextHeight;
\r
8021 newTextHeight = 0;
\r
8023 SetWindowPos(hText, NULL, 0, 0,
\r
8024 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8025 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8026 pt.x = rectInput.left;
\r
8027 pt.y = rectInput.top + newSizeY - sizeY;
\r
8028 ScreenToClient(hDlg, &pt);
\r
8029 SetWindowPos(hInput, NULL,
\r
8030 pt.x, pt.y, /* needs client coords */
\r
8031 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8032 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8038 case WM_GETMINMAXINFO:
\r
8039 /* Prevent resizing window too small */
\r
8040 mmi = (MINMAXINFO *) lParam;
\r
8041 mmi->ptMinTrackSize.x = 100;
\r
8042 mmi->ptMinTrackSize.y = 100;
\r
8045 /* [AS] Snapping */
\r
8046 case WM_ENTERSIZEMOVE:
\r
8047 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8050 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8053 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8055 case WM_EXITSIZEMOVE:
\r
8056 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8059 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8067 if (hwndConsole) return;
\r
8068 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8069 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8074 ConsoleOutput(char* data, int length, int forceVisible)
\r
8079 char buf[CO_MAX+1];
\r
8082 static int delayLF = 0;
\r
8083 CHARRANGE savesel, sel;
\r
8085 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8093 while (length--) {
\r
8101 } else if (*p == '\007') {
\r
8102 MyPlaySound(&sounds[(int)SoundBell]);
\r
8109 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8110 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8111 /* Save current selection */
\r
8112 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8113 exlen = GetWindowTextLength(hText);
\r
8114 /* Find out whether current end of text is visible */
\r
8115 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8116 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8117 /* Trim existing text if it's too long */
\r
8118 if (exlen + (q - buf) > CO_MAX) {
\r
8119 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8122 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8123 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8125 savesel.cpMin -= trim;
\r
8126 savesel.cpMax -= trim;
\r
8127 if (exlen < 0) exlen = 0;
\r
8128 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8129 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8131 /* Append the new text */
\r
8132 sel.cpMin = exlen;
\r
8133 sel.cpMax = exlen;
\r
8134 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8135 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8136 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8137 if (forceVisible || exlen == 0 ||
\r
8138 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8139 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8140 /* Scroll to make new end of text visible if old end of text
\r
8141 was visible or new text is an echo of user typein */
\r
8142 sel.cpMin = 9999999;
\r
8143 sel.cpMax = 9999999;
\r
8144 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8145 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8146 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8147 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8149 if (savesel.cpMax == exlen || forceVisible) {
\r
8150 /* Move insert point to new end of text if it was at the old
\r
8151 end of text or if the new text is an echo of user typein */
\r
8152 sel.cpMin = 9999999;
\r
8153 sel.cpMax = 9999999;
\r
8154 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8156 /* Restore previous selection */
\r
8157 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8159 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8166 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8170 COLORREF oldFg, oldBg;
\r
8174 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8176 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8177 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8178 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8181 rect.right = x + squareSize;
\r
8183 rect.bottom = y + squareSize;
\r
8186 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8187 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8188 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8189 &rect, str, strlen(str), NULL);
\r
8191 (void) SetTextColor(hdc, oldFg);
\r
8192 (void) SetBkColor(hdc, oldBg);
\r
8193 (void) SelectObject(hdc, oldFont);
\r
8197 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8198 RECT *rect, char *color, char *flagFell)
\r
8202 COLORREF oldFg, oldBg;
\r
8205 if (appData.clockMode) {
\r
8207 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8209 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8216 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8217 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8219 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8220 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8222 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8224 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8225 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8226 rect, str, strlen(str), NULL);
\r
8228 (void) SetTextColor(hdc, oldFg);
\r
8229 (void) SetBkColor(hdc, oldBg);
\r
8230 (void) SelectObject(hdc, oldFont);
\r
8235 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8241 if( count <= 0 ) {
\r
8242 if (appData.debugMode) {
\r
8243 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8246 return ERROR_INVALID_USER_BUFFER;
\r
8249 ResetEvent(ovl->hEvent);
\r
8250 ovl->Offset = ovl->OffsetHigh = 0;
\r
8251 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8255 err = GetLastError();
\r
8256 if (err == ERROR_IO_PENDING) {
\r
8257 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8261 err = GetLastError();
\r
8268 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8273 ResetEvent(ovl->hEvent);
\r
8274 ovl->Offset = ovl->OffsetHigh = 0;
\r
8275 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8279 err = GetLastError();
\r
8280 if (err == ERROR_IO_PENDING) {
\r
8281 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8285 err = GetLastError();
\r
8291 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8292 void CheckForInputBufferFull( InputSource * is )
\r
8294 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8295 /* Look for end of line */
\r
8296 char * p = is->buf;
\r
8298 while( p < is->next && *p != '\n' ) {
\r
8302 if( p >= is->next ) {
\r
8303 if (appData.debugMode) {
\r
8304 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8307 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8308 is->count = (DWORD) -1;
\r
8309 is->next = is->buf;
\r
8315 InputThread(LPVOID arg)
\r
8320 is = (InputSource *) arg;
\r
8321 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8322 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8323 while (is->hThread != NULL) {
\r
8324 is->error = DoReadFile(is->hFile, is->next,
\r
8325 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8326 &is->count, &ovl);
\r
8327 if (is->error == NO_ERROR) {
\r
8328 is->next += is->count;
\r
8330 if (is->error == ERROR_BROKEN_PIPE) {
\r
8331 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8334 is->count = (DWORD) -1;
\r
8335 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8340 CheckForInputBufferFull( is );
\r
8342 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8344 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8346 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8349 CloseHandle(ovl.hEvent);
\r
8350 CloseHandle(is->hFile);
\r
8352 if (appData.debugMode) {
\r
8353 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8360 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8362 NonOvlInputThread(LPVOID arg)
\r
8369 is = (InputSource *) arg;
\r
8370 while (is->hThread != NULL) {
\r
8371 is->error = ReadFile(is->hFile, is->next,
\r
8372 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8373 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8374 if (is->error == NO_ERROR) {
\r
8375 /* Change CRLF to LF */
\r
8376 if (is->next > is->buf) {
\r
8378 i = is->count + 1;
\r
8386 if (prev == '\r' && *p == '\n') {
\r
8398 if (is->error == ERROR_BROKEN_PIPE) {
\r
8399 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8402 is->count = (DWORD) -1;
\r
8406 CheckForInputBufferFull( is );
\r
8408 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8410 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8412 if (is->count < 0) break; /* Quit on error */
\r
8414 CloseHandle(is->hFile);
\r
8419 SocketInputThread(LPVOID arg)
\r
8423 is = (InputSource *) arg;
\r
8424 while (is->hThread != NULL) {
\r
8425 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8426 if ((int)is->count == SOCKET_ERROR) {
\r
8427 is->count = (DWORD) -1;
\r
8428 is->error = WSAGetLastError();
\r
8430 is->error = NO_ERROR;
\r
8431 is->next += is->count;
\r
8432 if (is->count == 0 && is->second == is) {
\r
8433 /* End of file on stderr; quit with no message */
\r
8437 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8439 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8441 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8447 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8451 is = (InputSource *) lParam;
\r
8452 if (is->lineByLine) {
\r
8453 /* Feed in lines one by one */
\r
8454 char *p = is->buf;
\r
8456 while (q < is->next) {
\r
8457 if (*q++ == '\n') {
\r
8458 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8463 /* Move any partial line to the start of the buffer */
\r
8465 while (p < is->next) {
\r
8470 if (is->error != NO_ERROR || is->count == 0) {
\r
8471 /* Notify backend of the error. Note: If there was a partial
\r
8472 line at the end, it is not flushed through. */
\r
8473 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8476 /* Feed in the whole chunk of input at once */
\r
8477 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8478 is->next = is->buf;
\r
8482 /*---------------------------------------------------------------------------*\
\r
8484 * Menu enables. Used when setting various modes.
\r
8486 \*---------------------------------------------------------------------------*/
\r
8494 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8496 while (enab->item > 0) {
\r
8497 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8502 Enables gnuEnables[] = {
\r
8503 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8504 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8505 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8516 Enables icsEnables[] = {
\r
8517 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8518 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8519 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8520 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8521 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8522 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8523 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8533 Enables zippyEnables[] = {
\r
8534 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8535 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8536 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8541 Enables ncpEnables[] = {
\r
8542 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8543 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8544 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8545 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8546 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8551 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8560 Enables trainingOnEnables[] = {
\r
8561 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8572 Enables trainingOffEnables[] = {
\r
8573 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8574 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8575 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8576 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8577 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8578 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8579 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8580 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8584 /* These modify either ncpEnables or gnuEnables */
\r
8585 Enables cmailEnables[] = {
\r
8586 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8588 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8589 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8591 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8596 Enables machineThinkingEnables[] = {
\r
8597 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8615 Enables userThinkingEnables[] = {
\r
8616 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8617 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8618 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8619 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8620 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8634 /*---------------------------------------------------------------------------*\
\r
8636 * Front-end interface functions exported by XBoard.
\r
8637 * Functions appear in same order as prototypes in frontend.h.
\r
8639 \*---------------------------------------------------------------------------*/
\r
8643 static UINT prevChecked = 0;
\r
8644 static int prevPausing = 0;
\r
8647 if (pausing != prevPausing) {
\r
8648 prevPausing = pausing;
\r
8649 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8650 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8651 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8654 switch (gameMode) {
\r
8655 case BeginningOfGame:
\r
8656 if (appData.icsActive)
\r
8657 nowChecked = IDM_IcsClient;
\r
8658 else if (appData.noChessProgram)
\r
8659 nowChecked = IDM_EditGame;
\r
8661 nowChecked = IDM_MachineBlack;
\r
8663 case MachinePlaysBlack:
\r
8664 nowChecked = IDM_MachineBlack;
\r
8666 case MachinePlaysWhite:
\r
8667 nowChecked = IDM_MachineWhite;
\r
8669 case TwoMachinesPlay:
\r
8670 nowChecked = IDM_TwoMachines;
\r
8673 nowChecked = IDM_AnalysisMode;
\r
8676 nowChecked = IDM_AnalyzeFile;
\r
8679 nowChecked = IDM_EditGame;
\r
8681 case PlayFromGameFile:
\r
8682 nowChecked = IDM_LoadGame;
\r
8684 case EditPosition:
\r
8685 nowChecked = IDM_EditPosition;
\r
8688 nowChecked = IDM_Training;
\r
8690 case IcsPlayingWhite:
\r
8691 case IcsPlayingBlack:
\r
8692 case IcsObserving:
\r
8694 nowChecked = IDM_IcsClient;
\r
8701 if (prevChecked != 0)
\r
8702 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8703 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8704 if (nowChecked != 0)
\r
8705 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8706 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8708 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8709 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8710 MF_BYCOMMAND|MF_ENABLED);
\r
8712 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8713 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8716 prevChecked = nowChecked;
\r
8718 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8719 if (appData.icsActive) {
\r
8720 if (appData.icsEngineAnalyze) {
\r
8721 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8722 MF_BYCOMMAND|MF_CHECKED);
\r
8724 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8725 MF_BYCOMMAND|MF_UNCHECKED);
\r
8733 HMENU hmenu = GetMenu(hwndMain);
\r
8734 SetMenuEnables(hmenu, icsEnables);
\r
8735 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8736 MF_BYPOSITION|MF_ENABLED);
\r
8738 if (appData.zippyPlay) {
\r
8739 SetMenuEnables(hmenu, zippyEnables);
\r
8740 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8741 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8742 MF_BYCOMMAND|MF_ENABLED);
\r
8750 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8756 HMENU hmenu = GetMenu(hwndMain);
\r
8757 SetMenuEnables(hmenu, ncpEnables);
\r
8758 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8759 MF_BYPOSITION|MF_GRAYED);
\r
8760 DrawMenuBar(hwndMain);
\r
8766 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8770 SetTrainingModeOn()
\r
8773 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8774 for (i = 0; i < N_BUTTONS; i++) {
\r
8775 if (buttonDesc[i].hwnd != NULL)
\r
8776 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8781 VOID SetTrainingModeOff()
\r
8784 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8785 for (i = 0; i < N_BUTTONS; i++) {
\r
8786 if (buttonDesc[i].hwnd != NULL)
\r
8787 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8793 SetUserThinkingEnables()
\r
8795 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8799 SetMachineThinkingEnables()
\r
8801 HMENU hMenu = GetMenu(hwndMain);
\r
8802 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8804 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8806 if (gameMode == MachinePlaysBlack) {
\r
8807 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8808 } else if (gameMode == MachinePlaysWhite) {
\r
8809 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8810 } else if (gameMode == TwoMachinesPlay) {
\r
8811 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8817 DisplayTitle(char *str)
\r
8819 char title[MSG_SIZ], *host;
\r
8820 if (str[0] != NULLCHAR) {
\r
8821 strcpy(title, str);
\r
8822 } else if (appData.icsActive) {
\r
8823 if (appData.icsCommPort[0] != NULLCHAR)
\r
8826 host = appData.icsHost;
\r
8827 sprintf(title, "%s: %s", szTitle, host);
\r
8828 } else if (appData.noChessProgram) {
\r
8829 strcpy(title, szTitle);
\r
8831 strcpy(title, szTitle);
\r
8832 strcat(title, ": ");
\r
8833 strcat(title, first.tidy);
\r
8835 SetWindowText(hwndMain, title);
\r
8840 DisplayMessage(char *str1, char *str2)
\r
8844 int remain = MESSAGE_TEXT_MAX - 1;
\r
8847 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8848 messageText[0] = NULLCHAR;
\r
8850 len = strlen(str1);
\r
8851 if (len > remain) len = remain;
\r
8852 strncpy(messageText, str1, len);
\r
8853 messageText[len] = NULLCHAR;
\r
8856 if (*str2 && remain >= 2) {
\r
8858 strcat(messageText, " ");
\r
8861 len = strlen(str2);
\r
8862 if (len > remain) len = remain;
\r
8863 strncat(messageText, str2, len);
\r
8865 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8867 if (IsIconic(hwndMain)) return;
\r
8868 hdc = GetDC(hwndMain);
\r
8869 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8870 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8871 &messageRect, messageText, strlen(messageText), NULL);
\r
8872 (void) SelectObject(hdc, oldFont);
\r
8873 (void) ReleaseDC(hwndMain, hdc);
\r
8877 DisplayError(char *str, int error)
\r
8879 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8885 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8886 NULL, error, LANG_NEUTRAL,
\r
8887 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8889 sprintf(buf, "%s:\n%s", str, buf2);
\r
8891 ErrorMap *em = errmap;
\r
8892 while (em->err != 0 && em->err != error) em++;
\r
8893 if (em->err != 0) {
\r
8894 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8896 sprintf(buf, "%s:\nError code %d", str, error);
\r
8901 ErrorPopUp("Error", buf);
\r
8906 DisplayMoveError(char *str)
\r
8908 fromX = fromY = -1;
\r
8909 ClearHighlights();
\r
8910 DrawPosition(FALSE, NULL);
\r
8911 if (appData.popupMoveErrors) {
\r
8912 ErrorPopUp("Error", str);
\r
8914 DisplayMessage(str, "");
\r
8915 moveErrorMessageUp = TRUE;
\r
8920 DisplayFatalError(char *str, int error, int exitStatus)
\r
8922 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8924 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8927 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8928 NULL, error, LANG_NEUTRAL,
\r
8929 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8931 sprintf(buf, "%s:\n%s", str, buf2);
\r
8933 ErrorMap *em = errmap;
\r
8934 while (em->err != 0 && em->err != error) em++;
\r
8935 if (em->err != 0) {
\r
8936 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8938 sprintf(buf, "%s:\nError code %d", str, error);
\r
8943 if (appData.debugMode) {
\r
8944 fprintf(debugFP, "%s: %s\n", label, str);
\r
8946 if (appData.popupExitMessage) {
\r
8947 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8948 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8950 ExitEvent(exitStatus);
\r
8955 DisplayInformation(char *str)
\r
8957 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8962 DisplayNote(char *str)
\r
8964 ErrorPopUp("Note", str);
\r
8969 char *title, *question, *replyPrefix;
\r
8974 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8976 static QuestionParams *qp;
\r
8977 char reply[MSG_SIZ];
\r
8980 switch (message) {
\r
8981 case WM_INITDIALOG:
\r
8982 qp = (QuestionParams *) lParam;
\r
8983 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8984 SetWindowText(hDlg, qp->title);
\r
8985 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8986 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8990 switch (LOWORD(wParam)) {
\r
8992 strcpy(reply, qp->replyPrefix);
\r
8993 if (*reply) strcat(reply, " ");
\r
8994 len = strlen(reply);
\r
8995 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8996 strcat(reply, "\n");
\r
8997 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8998 EndDialog(hDlg, TRUE);
\r
8999 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9002 EndDialog(hDlg, FALSE);
\r
9013 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9015 QuestionParams qp;
\r
9019 qp.question = question;
\r
9020 qp.replyPrefix = replyPrefix;
\r
9022 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9023 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9024 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9025 FreeProcInstance(lpProc);
\r
9028 /* [AS] Pick FRC position */
\r
9029 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9031 static int * lpIndexFRC;
\r
9037 case WM_INITDIALOG:
\r
9038 lpIndexFRC = (int *) lParam;
\r
9040 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9042 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9043 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9044 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9045 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9050 switch( LOWORD(wParam) ) {
\r
9052 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9053 EndDialog( hDlg, 0 );
\r
9054 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9057 EndDialog( hDlg, 1 );
\r
9059 case IDC_NFG_Edit:
\r
9060 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9061 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9063 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9066 case IDC_NFG_Random:
\r
9067 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9068 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9081 int index = appData.defaultFrcPosition;
\r
9082 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9084 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9086 if( result == 0 ) {
\r
9087 appData.defaultFrcPosition = index;
\r
9093 /* [AS] Game list options */
\r
9099 static GLT_Item GLT_ItemInfo[] = {
\r
9100 { GLT_EVENT, "Event" },
\r
9101 { GLT_SITE, "Site" },
\r
9102 { GLT_DATE, "Date" },
\r
9103 { GLT_ROUND, "Round" },
\r
9104 { GLT_PLAYERS, "Players" },
\r
9105 { GLT_RESULT, "Result" },
\r
9106 { GLT_WHITE_ELO, "White Rating" },
\r
9107 { GLT_BLACK_ELO, "Black Rating" },
\r
9108 { GLT_TIME_CONTROL,"Time Control" },
\r
9109 { GLT_VARIANT, "Variant" },
\r
9110 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9114 const char * GLT_FindItem( char id )
\r
9116 const char * result = 0;
\r
9118 GLT_Item * list = GLT_ItemInfo;
\r
9120 while( list->id != 0 ) {
\r
9121 if( list->id == id ) {
\r
9122 result = list->name;
\r
9132 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9134 const char * name = GLT_FindItem( id );
\r
9137 if( index >= 0 ) {
\r
9138 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9141 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9146 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9150 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9153 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9157 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9159 pc = GLT_ALL_TAGS;
\r
9162 if( strchr( tags, *pc ) == 0 ) {
\r
9163 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9168 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9171 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9173 char result = '\0';
\r
9176 GLT_Item * list = GLT_ItemInfo;
\r
9178 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9179 while( list->id != 0 ) {
\r
9180 if( strcmp( list->name, name ) == 0 ) {
\r
9181 result = list->id;
\r
9192 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9194 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9195 int idx2 = idx1 + delta;
\r
9196 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9198 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9201 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9202 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9203 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9204 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9208 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9210 static char glt[64];
\r
9211 static char * lpUserGLT;
\r
9215 case WM_INITDIALOG:
\r
9216 lpUserGLT = (char *) lParam;
\r
9218 strcpy( glt, lpUserGLT );
\r
9220 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9222 /* Initialize list */
\r
9223 GLT_TagsToList( hDlg, glt );
\r
9225 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9230 switch( LOWORD(wParam) ) {
\r
9233 char * pc = lpUserGLT;
\r
9235 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9239 id = GLT_ListItemToTag( hDlg, idx );
\r
9243 } while( id != '\0' );
\r
9245 EndDialog( hDlg, 0 );
\r
9248 EndDialog( hDlg, 1 );
\r
9251 case IDC_GLT_Default:
\r
9252 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9253 GLT_TagsToList( hDlg, glt );
\r
9256 case IDC_GLT_Restore:
\r
9257 strcpy( glt, lpUserGLT );
\r
9258 GLT_TagsToList( hDlg, glt );
\r
9262 GLT_MoveSelection( hDlg, -1 );
\r
9265 case IDC_GLT_Down:
\r
9266 GLT_MoveSelection( hDlg, +1 );
\r
9276 int GameListOptions()
\r
9280 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9282 strcpy( glt, appData.gameListTags );
\r
9284 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9286 if( result == 0 ) {
\r
9287 /* [AS] Memory leak here! */
\r
9288 appData.gameListTags = strdup( glt );
\r
9296 DisplayIcsInteractionTitle(char *str)
\r
9298 char consoleTitle[MSG_SIZ];
\r
9300 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9301 SetWindowText(hwndConsole, consoleTitle);
\r
9305 DrawPosition(int fullRedraw, Board board)
\r
9307 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9314 fromX = fromY = -1;
\r
9315 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9316 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9317 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9318 dragInfo.lastpos = dragInfo.pos;
\r
9319 dragInfo.start.x = dragInfo.start.y = -1;
\r
9320 dragInfo.from = dragInfo.start;
\r
9322 DrawPosition(TRUE, NULL);
\r
9328 CommentPopUp(char *title, char *str)
\r
9330 HWND hwnd = GetActiveWindow();
\r
9331 EitherCommentPopUp(0, title, str, FALSE);
\r
9332 SetActiveWindow(hwnd);
\r
9336 CommentPopDown(void)
\r
9338 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9339 if (commentDialog) {
\r
9340 ShowWindow(commentDialog, SW_HIDE);
\r
9342 commentDialogUp = FALSE;
\r
9346 EditCommentPopUp(int index, char *title, char *str)
\r
9348 EitherCommentPopUp(index, title, str, TRUE);
\r
9355 MyPlaySound(&sounds[(int)SoundMove]);
\r
9358 VOID PlayIcsWinSound()
\r
9360 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9363 VOID PlayIcsLossSound()
\r
9365 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9368 VOID PlayIcsDrawSound()
\r
9370 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9373 VOID PlayIcsUnfinishedSound()
\r
9375 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9381 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9389 consoleEcho = TRUE;
\r
9390 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9391 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9392 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9401 consoleEcho = FALSE;
\r
9402 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9403 /* This works OK: set text and background both to the same color */
\r
9405 cf.crTextColor = COLOR_ECHOOFF;
\r
9406 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9407 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9410 /* No Raw()...? */
\r
9412 void Colorize(ColorClass cc, int continuation)
\r
9414 currentColorClass = cc;
\r
9415 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9416 consoleCF.crTextColor = textAttribs[cc].color;
\r
9417 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9418 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9424 static char buf[MSG_SIZ];
\r
9425 DWORD bufsiz = MSG_SIZ;
\r
9427 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9428 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9430 if (!GetUserName(buf, &bufsiz)) {
\r
9431 /*DisplayError("Error getting user name", GetLastError());*/
\r
9432 strcpy(buf, "User");
\r
9440 static char buf[MSG_SIZ];
\r
9441 DWORD bufsiz = MSG_SIZ;
\r
9443 if (!GetComputerName(buf, &bufsiz)) {
\r
9444 /*DisplayError("Error getting host name", GetLastError());*/
\r
9445 strcpy(buf, "Unknown");
\r
9452 ClockTimerRunning()
\r
9454 return clockTimerEvent != 0;
\r
9460 if (clockTimerEvent == 0) return FALSE;
\r
9461 KillTimer(hwndMain, clockTimerEvent);
\r
9462 clockTimerEvent = 0;
\r
9467 StartClockTimer(long millisec)
\r
9469 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9470 (UINT) millisec, NULL);
\r
9474 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9477 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9479 if(appData.noGUI) return;
\r
9480 hdc = GetDC(hwndMain);
\r
9481 if (!IsIconic(hwndMain)) {
\r
9482 DisplayAClock(hdc, timeRemaining, highlight,
\r
9483 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9485 if (highlight && iconCurrent == iconBlack) {
\r
9486 iconCurrent = iconWhite;
\r
9487 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9488 if (IsIconic(hwndMain)) {
\r
9489 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9492 (void) ReleaseDC(hwndMain, hdc);
\r
9494 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9498 DisplayBlackClock(long timeRemaining, int highlight)
\r
9501 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9503 if(appData.noGUI) return;
\r
9504 hdc = GetDC(hwndMain);
\r
9505 if (!IsIconic(hwndMain)) {
\r
9506 DisplayAClock(hdc, timeRemaining, highlight,
\r
9507 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9509 if (highlight && iconCurrent == iconWhite) {
\r
9510 iconCurrent = iconBlack;
\r
9511 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9512 if (IsIconic(hwndMain)) {
\r
9513 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9516 (void) ReleaseDC(hwndMain, hdc);
\r
9518 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9523 LoadGameTimerRunning()
\r
9525 return loadGameTimerEvent != 0;
\r
9529 StopLoadGameTimer()
\r
9531 if (loadGameTimerEvent == 0) return FALSE;
\r
9532 KillTimer(hwndMain, loadGameTimerEvent);
\r
9533 loadGameTimerEvent = 0;
\r
9538 StartLoadGameTimer(long millisec)
\r
9540 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9541 (UINT) millisec, NULL);
\r
9549 char fileTitle[MSG_SIZ];
\r
9551 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9552 f = OpenFileDialog(hwndMain, "a", defName,
\r
9553 appData.oldSaveStyle ? "gam" : "pgn",
\r
9555 "Save Game to File", NULL, fileTitle, NULL);
\r
9557 SaveGame(f, 0, "");
\r
9564 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9566 if (delayedTimerEvent != 0) {
\r
9567 if (appData.debugMode) {
\r
9568 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9570 KillTimer(hwndMain, delayedTimerEvent);
\r
9571 delayedTimerEvent = 0;
\r
9572 delayedTimerCallback();
\r
9574 delayedTimerCallback = cb;
\r
9575 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9576 (UINT) millisec, NULL);
\r
9579 DelayedEventCallback
\r
9582 if (delayedTimerEvent) {
\r
9583 return delayedTimerCallback;
\r
9590 CancelDelayedEvent()
\r
9592 if (delayedTimerEvent) {
\r
9593 KillTimer(hwndMain, delayedTimerEvent);
\r
9594 delayedTimerEvent = 0;
\r
9598 DWORD GetWin32Priority(int nice)
\r
9599 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9601 REALTIME_PRIORITY_CLASS 0x00000100
\r
9602 HIGH_PRIORITY_CLASS 0x00000080
\r
9603 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9604 NORMAL_PRIORITY_CLASS 0x00000020
\r
9605 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9606 IDLE_PRIORITY_CLASS 0x00000040
\r
9608 if (nice < -15) return 0x00000080;
\r
9609 if (nice < 0) return 0x00008000;
\r
9610 if (nice == 0) return 0x00000020;
\r
9611 if (nice < 15) return 0x00004000;
\r
9612 return 0x00000040;
\r
9615 /* Start a child process running the given program.
\r
9616 The process's standard output can be read from "from", and its
\r
9617 standard input can be written to "to".
\r
9618 Exit with fatal error if anything goes wrong.
\r
9619 Returns an opaque pointer that can be used to destroy the process
\r
9623 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9625 #define BUFSIZE 4096
\r
9627 HANDLE hChildStdinRd, hChildStdinWr,
\r
9628 hChildStdoutRd, hChildStdoutWr;
\r
9629 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9630 SECURITY_ATTRIBUTES saAttr;
\r
9632 PROCESS_INFORMATION piProcInfo;
\r
9633 STARTUPINFO siStartInfo;
\r
9635 char buf[MSG_SIZ];
\r
9638 if (appData.debugMode) {
\r
9639 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9644 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9645 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9646 saAttr.bInheritHandle = TRUE;
\r
9647 saAttr.lpSecurityDescriptor = NULL;
\r
9650 * The steps for redirecting child's STDOUT:
\r
9651 * 1. Create anonymous pipe to be STDOUT for child.
\r
9652 * 2. Create a noninheritable duplicate of read handle,
\r
9653 * and close the inheritable read handle.
\r
9656 /* Create a pipe for the child's STDOUT. */
\r
9657 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9658 return GetLastError();
\r
9661 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9662 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9663 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9664 FALSE, /* not inherited */
\r
9665 DUPLICATE_SAME_ACCESS);
\r
9667 return GetLastError();
\r
9669 CloseHandle(hChildStdoutRd);
\r
9672 * The steps for redirecting child's STDIN:
\r
9673 * 1. Create anonymous pipe to be STDIN for child.
\r
9674 * 2. Create a noninheritable duplicate of write handle,
\r
9675 * and close the inheritable write handle.
\r
9678 /* Create a pipe for the child's STDIN. */
\r
9679 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9680 return GetLastError();
\r
9683 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9684 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9685 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9686 FALSE, /* not inherited */
\r
9687 DUPLICATE_SAME_ACCESS);
\r
9689 return GetLastError();
\r
9691 CloseHandle(hChildStdinWr);
\r
9693 /* Arrange to (1) look in dir for the child .exe file, and
\r
9694 * (2) have dir be the child's working directory. Interpret
\r
9695 * dir relative to the directory WinBoard loaded from. */
\r
9696 GetCurrentDirectory(MSG_SIZ, buf);
\r
9697 SetCurrentDirectory(installDir);
\r
9698 SetCurrentDirectory(dir);
\r
9700 /* Now create the child process. */
\r
9702 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9703 siStartInfo.lpReserved = NULL;
\r
9704 siStartInfo.lpDesktop = NULL;
\r
9705 siStartInfo.lpTitle = NULL;
\r
9706 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9707 siStartInfo.cbReserved2 = 0;
\r
9708 siStartInfo.lpReserved2 = NULL;
\r
9709 siStartInfo.hStdInput = hChildStdinRd;
\r
9710 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9711 siStartInfo.hStdError = hChildStdoutWr;
\r
9713 fSuccess = CreateProcess(NULL,
\r
9714 cmdLine, /* command line */
\r
9715 NULL, /* process security attributes */
\r
9716 NULL, /* primary thread security attrs */
\r
9717 TRUE, /* handles are inherited */
\r
9718 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9719 NULL, /* use parent's environment */
\r
9721 &siStartInfo, /* STARTUPINFO pointer */
\r
9722 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9724 err = GetLastError();
\r
9725 SetCurrentDirectory(buf); /* return to prev directory */
\r
9730 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9731 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9732 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9735 /* Close the handles we don't need in the parent */
\r
9736 CloseHandle(piProcInfo.hThread);
\r
9737 CloseHandle(hChildStdinRd);
\r
9738 CloseHandle(hChildStdoutWr);
\r
9740 /* Prepare return value */
\r
9741 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9742 cp->kind = CPReal;
\r
9743 cp->hProcess = piProcInfo.hProcess;
\r
9744 cp->pid = piProcInfo.dwProcessId;
\r
9745 cp->hFrom = hChildStdoutRdDup;
\r
9746 cp->hTo = hChildStdinWrDup;
\r
9748 *pr = (void *) cp;
\r
9750 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9751 2000 where engines sometimes don't see the initial command(s)
\r
9752 from WinBoard and hang. I don't understand how that can happen,
\r
9753 but the Sleep is harmless, so I've put it in. Others have also
\r
9754 reported what may be the same problem, so hopefully this will fix
\r
9755 it for them too. */
\r
9763 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9765 ChildProc *cp; int result;
\r
9767 cp = (ChildProc *) pr;
\r
9768 if (cp == NULL) return;
\r
9770 switch (cp->kind) {
\r
9772 /* TerminateProcess is considered harmful, so... */
\r
9773 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9774 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9775 /* The following doesn't work because the chess program
\r
9776 doesn't "have the same console" as WinBoard. Maybe
\r
9777 we could arrange for this even though neither WinBoard
\r
9778 nor the chess program uses a console for stdio? */
\r
9779 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9781 /* [AS] Special termination modes for misbehaving programs... */
\r
9782 if( signal == 9 ) {
\r
9783 result = TerminateProcess( cp->hProcess, 0 );
\r
9785 if ( appData.debugMode) {
\r
9786 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9789 else if( signal == 10 ) {
\r
9790 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9792 if( dw != WAIT_OBJECT_0 ) {
\r
9793 result = TerminateProcess( cp->hProcess, 0 );
\r
9795 if ( appData.debugMode) {
\r
9796 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9802 CloseHandle(cp->hProcess);
\r
9806 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9810 closesocket(cp->sock);
\r
9815 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9816 closesocket(cp->sock);
\r
9817 closesocket(cp->sock2);
\r
9825 InterruptChildProcess(ProcRef pr)
\r
9829 cp = (ChildProc *) pr;
\r
9830 if (cp == NULL) return;
\r
9831 switch (cp->kind) {
\r
9833 /* The following doesn't work because the chess program
\r
9834 doesn't "have the same console" as WinBoard. Maybe
\r
9835 we could arrange for this even though neither WinBoard
\r
9836 nor the chess program uses a console for stdio */
\r
9837 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9842 /* Can't interrupt */
\r
9846 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9853 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9855 char cmdLine[MSG_SIZ];
\r
9857 if (port[0] == NULLCHAR) {
\r
9858 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9860 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9862 return StartChildProcess(cmdLine, "", pr);
\r
9866 /* Code to open TCP sockets */
\r
9869 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9874 struct sockaddr_in sa, mysa;
\r
9875 struct hostent FAR *hp;
\r
9876 unsigned short uport;
\r
9877 WORD wVersionRequested;
\r
9880 /* Initialize socket DLL */
\r
9881 wVersionRequested = MAKEWORD(1, 1);
\r
9882 err = WSAStartup(wVersionRequested, &wsaData);
\r
9883 if (err != 0) return err;
\r
9886 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9887 err = WSAGetLastError();
\r
9892 /* Bind local address using (mostly) don't-care values.
\r
9894 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9895 mysa.sin_family = AF_INET;
\r
9896 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9897 uport = (unsigned short) 0;
\r
9898 mysa.sin_port = htons(uport);
\r
9899 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9900 == SOCKET_ERROR) {
\r
9901 err = WSAGetLastError();
\r
9906 /* Resolve remote host name */
\r
9907 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9908 if (!(hp = gethostbyname(host))) {
\r
9909 unsigned int b0, b1, b2, b3;
\r
9911 err = WSAGetLastError();
\r
9913 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9914 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9915 hp->h_addrtype = AF_INET;
\r
9917 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9918 hp->h_addr_list[0] = (char *) malloc(4);
\r
9919 hp->h_addr_list[0][0] = (char) b0;
\r
9920 hp->h_addr_list[0][1] = (char) b1;
\r
9921 hp->h_addr_list[0][2] = (char) b2;
\r
9922 hp->h_addr_list[0][3] = (char) b3;
\r
9928 sa.sin_family = hp->h_addrtype;
\r
9929 uport = (unsigned short) atoi(port);
\r
9930 sa.sin_port = htons(uport);
\r
9931 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9933 /* Make connection */
\r
9934 if (connect(s, (struct sockaddr *) &sa,
\r
9935 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9936 err = WSAGetLastError();
\r
9941 /* Prepare return value */
\r
9942 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9943 cp->kind = CPSock;
\r
9945 *pr = (ProcRef *) cp;
\r
9951 OpenCommPort(char *name, ProcRef *pr)
\r
9956 char fullname[MSG_SIZ];
\r
9958 if (*name != '\\')
\r
9959 sprintf(fullname, "\\\\.\\%s", name);
\r
9961 strcpy(fullname, name);
\r
9963 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9964 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9965 if (h == (HANDLE) -1) {
\r
9966 return GetLastError();
\r
9970 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9972 /* Accumulate characters until a 100ms pause, then parse */
\r
9973 ct.ReadIntervalTimeout = 100;
\r
9974 ct.ReadTotalTimeoutMultiplier = 0;
\r
9975 ct.ReadTotalTimeoutConstant = 0;
\r
9976 ct.WriteTotalTimeoutMultiplier = 0;
\r
9977 ct.WriteTotalTimeoutConstant = 0;
\r
9978 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9980 /* Prepare return value */
\r
9981 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9982 cp->kind = CPComm;
\r
9985 *pr = (ProcRef *) cp;
\r
9991 OpenLoopback(ProcRef *pr)
\r
9993 DisplayFatalError("Not implemented", 0, 1);
\r
9999 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10003 SOCKET s, s2, s3;
\r
10004 struct sockaddr_in sa, mysa;
\r
10005 struct hostent FAR *hp;
\r
10006 unsigned short uport;
\r
10007 WORD wVersionRequested;
\r
10010 char stderrPortStr[MSG_SIZ];
\r
10012 /* Initialize socket DLL */
\r
10013 wVersionRequested = MAKEWORD(1, 1);
\r
10014 err = WSAStartup(wVersionRequested, &wsaData);
\r
10015 if (err != 0) return err;
\r
10017 /* Resolve remote host name */
\r
10018 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10019 if (!(hp = gethostbyname(host))) {
\r
10020 unsigned int b0, b1, b2, b3;
\r
10022 err = WSAGetLastError();
\r
10024 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10025 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10026 hp->h_addrtype = AF_INET;
\r
10027 hp->h_length = 4;
\r
10028 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10029 hp->h_addr_list[0] = (char *) malloc(4);
\r
10030 hp->h_addr_list[0][0] = (char) b0;
\r
10031 hp->h_addr_list[0][1] = (char) b1;
\r
10032 hp->h_addr_list[0][2] = (char) b2;
\r
10033 hp->h_addr_list[0][3] = (char) b3;
\r
10039 sa.sin_family = hp->h_addrtype;
\r
10040 uport = (unsigned short) 514;
\r
10041 sa.sin_port = htons(uport);
\r
10042 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10044 /* Bind local socket to unused "privileged" port address
\r
10046 s = INVALID_SOCKET;
\r
10047 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10048 mysa.sin_family = AF_INET;
\r
10049 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10050 for (fromPort = 1023;; fromPort--) {
\r
10051 if (fromPort < 0) {
\r
10053 return WSAEADDRINUSE;
\r
10055 if (s == INVALID_SOCKET) {
\r
10056 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10057 err = WSAGetLastError();
\r
10062 uport = (unsigned short) fromPort;
\r
10063 mysa.sin_port = htons(uport);
\r
10064 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10065 == SOCKET_ERROR) {
\r
10066 err = WSAGetLastError();
\r
10067 if (err == WSAEADDRINUSE) continue;
\r
10071 if (connect(s, (struct sockaddr *) &sa,
\r
10072 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10073 err = WSAGetLastError();
\r
10074 if (err == WSAEADDRINUSE) {
\r
10085 /* Bind stderr local socket to unused "privileged" port address
\r
10087 s2 = INVALID_SOCKET;
\r
10088 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10089 mysa.sin_family = AF_INET;
\r
10090 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10091 for (fromPort = 1023;; fromPort--) {
\r
10092 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10093 if (fromPort < 0) {
\r
10094 (void) closesocket(s);
\r
10096 return WSAEADDRINUSE;
\r
10098 if (s2 == INVALID_SOCKET) {
\r
10099 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10100 err = WSAGetLastError();
\r
10106 uport = (unsigned short) fromPort;
\r
10107 mysa.sin_port = htons(uport);
\r
10108 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10109 == SOCKET_ERROR) {
\r
10110 err = WSAGetLastError();
\r
10111 if (err == WSAEADDRINUSE) continue;
\r
10112 (void) closesocket(s);
\r
10116 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10117 err = WSAGetLastError();
\r
10118 if (err == WSAEADDRINUSE) {
\r
10120 s2 = INVALID_SOCKET;
\r
10123 (void) closesocket(s);
\r
10124 (void) closesocket(s2);
\r
10130 prevStderrPort = fromPort; // remember port used
\r
10131 sprintf(stderrPortStr, "%d", fromPort);
\r
10133 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10134 err = WSAGetLastError();
\r
10135 (void) closesocket(s);
\r
10136 (void) closesocket(s2);
\r
10141 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10142 err = WSAGetLastError();
\r
10143 (void) closesocket(s);
\r
10144 (void) closesocket(s2);
\r
10148 if (*user == NULLCHAR) user = UserName();
\r
10149 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10150 err = WSAGetLastError();
\r
10151 (void) closesocket(s);
\r
10152 (void) closesocket(s2);
\r
10156 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10157 err = WSAGetLastError();
\r
10158 (void) closesocket(s);
\r
10159 (void) closesocket(s2);
\r
10164 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10165 err = WSAGetLastError();
\r
10166 (void) closesocket(s);
\r
10167 (void) closesocket(s2);
\r
10171 (void) closesocket(s2); /* Stop listening */
\r
10173 /* Prepare return value */
\r
10174 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10175 cp->kind = CPRcmd;
\r
10178 *pr = (ProcRef *) cp;
\r
10185 AddInputSource(ProcRef pr, int lineByLine,
\r
10186 InputCallback func, VOIDSTAR closure)
\r
10188 InputSource *is, *is2 = NULL;
\r
10189 ChildProc *cp = (ChildProc *) pr;
\r
10191 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10192 is->lineByLine = lineByLine;
\r
10194 is->closure = closure;
\r
10195 is->second = NULL;
\r
10196 is->next = is->buf;
\r
10197 if (pr == NoProc) {
\r
10198 is->kind = CPReal;
\r
10199 consoleInputSource = is;
\r
10201 is->kind = cp->kind;
\r
10203 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10204 we create all threads suspended so that the is->hThread variable can be
\r
10205 safely assigned, then let the threads start with ResumeThread.
\r
10207 switch (cp->kind) {
\r
10209 is->hFile = cp->hFrom;
\r
10210 cp->hFrom = NULL; /* now owned by InputThread */
\r
10212 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10213 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10217 is->hFile = cp->hFrom;
\r
10218 cp->hFrom = NULL; /* now owned by InputThread */
\r
10220 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10221 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10225 is->sock = cp->sock;
\r
10227 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10228 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10232 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10234 is->sock = cp->sock;
\r
10235 is->second = is2;
\r
10236 is2->sock = cp->sock2;
\r
10237 is2->second = is2;
\r
10239 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10240 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10242 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10243 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10247 if( is->hThread != NULL ) {
\r
10248 ResumeThread( is->hThread );
\r
10251 if( is2 != NULL && is2->hThread != NULL ) {
\r
10252 ResumeThread( is2->hThread );
\r
10256 return (InputSourceRef) is;
\r
10260 RemoveInputSource(InputSourceRef isr)
\r
10264 is = (InputSource *) isr;
\r
10265 is->hThread = NULL; /* tell thread to stop */
\r
10266 CloseHandle(is->hThread);
\r
10267 if (is->second != NULL) {
\r
10268 is->second->hThread = NULL;
\r
10269 CloseHandle(is->second->hThread);
\r
10275 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10278 int outCount = SOCKET_ERROR;
\r
10279 ChildProc *cp = (ChildProc *) pr;
\r
10280 static OVERLAPPED ovl;
\r
10282 if (pr == NoProc) {
\r
10283 ConsoleOutput(message, count, FALSE);
\r
10287 if (ovl.hEvent == NULL) {
\r
10288 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10290 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10292 switch (cp->kind) {
\r
10295 outCount = send(cp->sock, message, count, 0);
\r
10296 if (outCount == SOCKET_ERROR) {
\r
10297 *outError = WSAGetLastError();
\r
10299 *outError = NO_ERROR;
\r
10304 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10305 &dOutCount, NULL)) {
\r
10306 *outError = NO_ERROR;
\r
10307 outCount = (int) dOutCount;
\r
10309 *outError = GetLastError();
\r
10314 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10315 &dOutCount, &ovl);
\r
10316 if (*outError == NO_ERROR) {
\r
10317 outCount = (int) dOutCount;
\r
10325 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10328 /* Ignore delay, not implemented for WinBoard */
\r
10329 return OutputToProcess(pr, message, count, outError);
\r
10334 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10335 char *buf, int count, int error)
\r
10337 DisplayFatalError("Not implemented", 0, 1);
\r
10340 /* see wgamelist.c for Game List functions */
\r
10341 /* see wedittags.c for Edit Tags functions */
\r
10348 char buf[MSG_SIZ];
\r
10351 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10352 f = fopen(buf, "r");
\r
10354 ProcessICSInitScript(f);
\r
10362 StartAnalysisClock()
\r
10364 if (analysisTimerEvent) return;
\r
10365 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10366 (UINT) 2000, NULL);
\r
10370 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10372 static HANDLE hwndText;
\r
10374 static int sizeX, sizeY;
\r
10375 int newSizeX, newSizeY, flags;
\r
10378 switch (message) {
\r
10379 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10380 /* Initialize the dialog items */
\r
10381 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10382 SetWindowText(hDlg, analysisTitle);
\r
10383 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10384 /* Size and position the dialog */
\r
10385 if (!analysisDialog) {
\r
10386 analysisDialog = hDlg;
\r
10387 flags = SWP_NOZORDER;
\r
10388 GetClientRect(hDlg, &rect);
\r
10389 sizeX = rect.right;
\r
10390 sizeY = rect.bottom;
\r
10391 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10392 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10393 WINDOWPLACEMENT wp;
\r
10394 EnsureOnScreen(&analysisX, &analysisY);
\r
10395 wp.length = sizeof(WINDOWPLACEMENT);
\r
10397 wp.showCmd = SW_SHOW;
\r
10398 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10399 wp.rcNormalPosition.left = analysisX;
\r
10400 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10401 wp.rcNormalPosition.top = analysisY;
\r
10402 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10403 SetWindowPlacement(hDlg, &wp);
\r
10405 GetClientRect(hDlg, &rect);
\r
10406 newSizeX = rect.right;
\r
10407 newSizeY = rect.bottom;
\r
10408 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10409 newSizeX, newSizeY);
\r
10410 sizeX = newSizeX;
\r
10411 sizeY = newSizeY;
\r
10416 case WM_COMMAND: /* message: received a command */
\r
10417 switch (LOWORD(wParam)) {
\r
10419 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10420 ExitAnalyzeMode();
\r
10432 newSizeX = LOWORD(lParam);
\r
10433 newSizeY = HIWORD(lParam);
\r
10434 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10435 sizeX = newSizeX;
\r
10436 sizeY = newSizeY;
\r
10439 case WM_GETMINMAXINFO:
\r
10440 /* Prevent resizing window too small */
\r
10441 mmi = (MINMAXINFO *) lParam;
\r
10442 mmi->ptMinTrackSize.x = 100;
\r
10443 mmi->ptMinTrackSize.y = 100;
\r
10450 AnalysisPopUp(char* title, char* str)
\r
10456 EngineOutputPopUp();
\r
10459 if (str == NULL) str = "";
\r
10460 p = (char *) malloc(2 * strlen(str) + 2);
\r
10463 if (*str == '\n') *q++ = '\r';
\r
10467 if (analysisText != NULL) free(analysisText);
\r
10468 analysisText = p;
\r
10470 if (analysisDialog) {
\r
10471 SetWindowText(analysisDialog, title);
\r
10472 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10473 ShowWindow(analysisDialog, SW_SHOW);
\r
10475 analysisTitle = title;
\r
10476 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10477 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10478 hwndMain, (DLGPROC)lpProc);
\r
10479 FreeProcInstance(lpProc);
\r
10481 analysisDialogUp = TRUE;
\r
10485 AnalysisPopDown()
\r
10487 if (analysisDialog) {
\r
10488 ShowWindow(analysisDialog, SW_HIDE);
\r
10490 analysisDialogUp = FALSE;
\r
10495 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10497 highlightInfo.sq[0].x = fromX;
\r
10498 highlightInfo.sq[0].y = fromY;
\r
10499 highlightInfo.sq[1].x = toX;
\r
10500 highlightInfo.sq[1].y = toY;
\r
10504 ClearHighlights()
\r
10506 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10507 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10511 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10513 premoveHighlightInfo.sq[0].x = fromX;
\r
10514 premoveHighlightInfo.sq[0].y = fromY;
\r
10515 premoveHighlightInfo.sq[1].x = toX;
\r
10516 premoveHighlightInfo.sq[1].y = toY;
\r
10520 ClearPremoveHighlights()
\r
10522 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10523 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10527 ShutDownFrontEnd()
\r
10529 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10530 DeleteClipboardTempFiles();
\r
10536 if (IsIconic(hwndMain))
\r
10537 ShowWindow(hwndMain, SW_RESTORE);
\r
10539 SetActiveWindow(hwndMain);
\r
10543 * Prototypes for animation support routines
\r
10545 static void ScreenSquare(int column, int row, POINT * pt);
\r
10546 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10547 POINT frames[], int * nFrames);
\r
10550 #define kFactor 4
\r
10553 AnimateMove(board, fromX, fromY, toX, toY)
\r
10560 ChessSquare piece;
\r
10561 POINT start, finish, mid;
\r
10562 POINT frames[kFactor * 2 + 1];
\r
10565 if (!appData.animate) return;
\r
10566 if (doingSizing) return;
\r
10567 if (fromY < 0 || fromX < 0) return;
\r
10568 piece = board[fromY][fromX];
\r
10569 if (piece >= EmptySquare) return;
\r
10571 ScreenSquare(fromX, fromY, &start);
\r
10572 ScreenSquare(toX, toY, &finish);
\r
10574 /* All pieces except knights move in straight line */
\r
10575 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10576 mid.x = start.x + (finish.x - start.x) / 2;
\r
10577 mid.y = start.y + (finish.y - start.y) / 2;
\r
10579 /* Knight: make diagonal movement then straight */
\r
10580 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10581 mid.x = start.x + (finish.x - start.x) / 2;
\r
10582 mid.y = finish.y;
\r
10584 mid.x = finish.x;
\r
10585 mid.y = start.y + (finish.y - start.y) / 2;
\r
10589 /* Don't use as many frames for very short moves */
\r
10590 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10591 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10593 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10595 animInfo.from.x = fromX;
\r
10596 animInfo.from.y = fromY;
\r
10597 animInfo.to.x = toX;
\r
10598 animInfo.to.y = toY;
\r
10599 animInfo.lastpos = start;
\r
10600 animInfo.piece = piece;
\r
10601 for (n = 0; n < nFrames; n++) {
\r
10602 animInfo.pos = frames[n];
\r
10603 DrawPosition(FALSE, NULL);
\r
10604 animInfo.lastpos = animInfo.pos;
\r
10605 Sleep(appData.animSpeed);
\r
10607 animInfo.pos = finish;
\r
10608 DrawPosition(FALSE, NULL);
\r
10609 animInfo.piece = EmptySquare;
\r
10612 /* Convert board position to corner of screen rect and color */
\r
10615 ScreenSquare(column, row, pt)
\r
10616 int column; int row; POINT * pt;
\r
10619 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10620 pt->y = lineGap + row * (squareSize + lineGap);
\r
10622 pt->x = lineGap + column * (squareSize + lineGap);
\r
10623 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10627 /* Generate a series of frame coords from start->mid->finish.
\r
10628 The movement rate doubles until the half way point is
\r
10629 reached, then halves back down to the final destination,
\r
10630 which gives a nice slow in/out effect. The algorithmn
\r
10631 may seem to generate too many intermediates for short
\r
10632 moves, but remember that the purpose is to attract the
\r
10633 viewers attention to the piece about to be moved and
\r
10634 then to where it ends up. Too few frames would be less
\r
10638 Tween(start, mid, finish, factor, frames, nFrames)
\r
10639 POINT * start; POINT * mid;
\r
10640 POINT * finish; int factor;
\r
10641 POINT frames[]; int * nFrames;
\r
10643 int n, fraction = 1, count = 0;
\r
10645 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10646 for (n = 0; n < factor; n++)
\r
10648 for (n = 0; n < factor; n++) {
\r
10649 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10650 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10652 fraction = fraction / 2;
\r
10656 frames[count] = *mid;
\r
10659 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10661 for (n = 0; n < factor; n++) {
\r
10662 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10663 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10665 fraction = fraction * 2;
\r
10667 *nFrames = count;
\r
10671 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10676 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10677 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10679 OutputDebugString( buf );
\r
10682 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10684 EvalGraphSet( first, last, current, pvInfoList );
\r
10687 void SetProgramStats( FrontEndProgramStats * stats )
\r
10692 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10693 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10695 OutputDebugString( buf );
\r
10698 EngineOutputUpdate( stats );
\r