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
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
80 #include "winboard.h"
\r
81 #include "frontend.h"
\r
82 #include "backend.h"
\r
84 #include "wclipbrd.h"
\r
85 #include "wgamelist.h"
\r
86 #include "wedittags.h"
\r
87 #include "woptions.h"
\r
88 #include "wsockerr.h"
\r
89 #include "defaults.h"
\r
93 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
96 void mysrandom(unsigned int seed);
\r
98 extern int whiteFlag, blackFlag;
\r
99 Boolean flipClock = FALSE;
\r
101 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
104 ChessSquare piece;
\r
105 POINT pos; /* window coordinates of current pos */
\r
106 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
107 POINT from; /* board coordinates of the piece's orig pos */
\r
108 POINT to; /* board coordinates of the piece's new pos */
\r
111 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
114 POINT start; /* window coordinates of start pos */
\r
115 POINT pos; /* window coordinates of current pos */
\r
116 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
117 POINT from; /* board coordinates of the piece's orig pos */
\r
120 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT sq[2]; /* board coordinates of from, to squares */
\r
126 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
127 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
129 /* Window class names */
\r
130 char szAppName[] = "WinBoard";
\r
131 char szConsoleName[] = "WBConsole";
\r
133 /* Title bar text */
\r
134 char szTitle[] = "WinBoard";
\r
135 char szConsoleTitle[] = "ICS Interaction";
\r
138 char *settingsFileName;
\r
139 BOOLEAN saveSettingsOnExit;
\r
140 char installDir[MSG_SIZ];
\r
142 BoardSize boardSize;
\r
143 BOOLEAN chessProgram;
\r
144 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
145 static int squareSize, lineGap, minorSize;
\r
146 static int winWidth, winHeight;
\r
147 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
148 static int logoHeight = 0;
\r
149 static char messageText[MESSAGE_TEXT_MAX];
\r
150 static int clockTimerEvent = 0;
\r
151 static int loadGameTimerEvent = 0;
\r
152 static int analysisTimerEvent = 0;
\r
153 static DelayedEventCallback delayedTimerCallback;
\r
154 static int delayedTimerEvent = 0;
\r
155 static int buttonCount = 2;
\r
156 char *icsTextMenuString;
\r
158 char *firstChessProgramNames;
\r
159 char *secondChessProgramNames;
\r
161 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
163 #define PALETTESIZE 256
\r
165 HINSTANCE hInst; /* current instance */
\r
166 HWND hwndMain = NULL; /* root window*/
\r
167 HWND hwndConsole = NULL;
\r
168 BOOLEAN alwaysOnTop = FALSE;
\r
170 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
171 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
173 ColorClass currentColorClass;
\r
175 HWND hCommPort = NULL; /* currently open comm port */
\r
176 static HWND hwndPause; /* pause button */
\r
177 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
178 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
179 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
180 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
181 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
182 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
183 static HPEN gridPen = NULL;
\r
184 static HPEN highlightPen = NULL;
\r
185 static HPEN premovePen = NULL;
\r
186 static NPLOGPALETTE pLogPal;
\r
187 static BOOL paletteChanged = FALSE;
\r
188 static HICON iconWhite, iconBlack, iconCurrent;
\r
189 static int doingSizing = FALSE;
\r
190 static int lastSizing = 0;
\r
191 static int prevStderrPort;
\r
193 /* [AS] Support for background textures */
\r
194 #define BACK_TEXTURE_MODE_DISABLED 0
\r
195 #define BACK_TEXTURE_MODE_PLAIN 1
\r
196 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
198 static HBITMAP liteBackTexture = NULL;
\r
199 static HBITMAP darkBackTexture = NULL;
\r
200 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
201 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
202 static int backTextureSquareSize = 0;
\r
203 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
205 #if __GNUC__ && !defined(_winmajor)
\r
206 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
208 #define oldDialog (_winmajor < 4)
\r
211 char *defaultTextAttribs[] =
\r
213 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
214 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
224 int cliWidth, cliHeight;
\r
227 SizeInfo sizeInfo[] =
\r
229 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
230 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
231 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
232 { "petite", 33, 1, 1, 1, 0, 0 },
\r
233 { "slim", 37, 2, 1, 0, 0, 0 },
\r
234 { "small", 40, 2, 1, 0, 0, 0 },
\r
235 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
236 { "middling", 49, 2, 0, 0, 0, 0 },
\r
237 { "average", 54, 2, 0, 0, 0, 0 },
\r
238 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
239 { "medium", 64, 3, 0, 0, 0, 0 },
\r
240 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
241 { "large", 80, 3, 0, 0, 0, 0 },
\r
242 { "big", 87, 3, 0, 0, 0, 0 },
\r
243 { "huge", 95, 3, 0, 0, 0, 0 },
\r
244 { "giant", 108, 3, 0, 0, 0, 0 },
\r
245 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
246 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
247 { NULL, 0, 0, 0, 0, 0, 0 }
\r
250 #define MF(x) {x, {0, }, {0, }, 0}
\r
251 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
273 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
282 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
283 #define N_BUTTONS 5
\r
285 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
287 {"<<", IDM_ToStart, NULL, NULL},
\r
288 {"<", IDM_Backward, NULL, NULL},
\r
289 {"P", IDM_Pause, NULL, NULL},
\r
290 {">", IDM_Forward, NULL, NULL},
\r
291 {">>", IDM_ToEnd, NULL, NULL},
\r
294 int tinyLayout = 0, smallLayout = 0;
\r
295 #define MENU_BAR_ITEMS 6
\r
296 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
297 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
298 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
302 MySound sounds[(int)NSoundClasses];
\r
303 MyTextAttribs textAttribs[(int)NColorClasses];
\r
305 MyColorizeAttribs colorizeAttribs[] = {
\r
306 { (COLORREF)0, 0, "Shout Text" },
\r
307 { (COLORREF)0, 0, "SShout/CShout" },
\r
308 { (COLORREF)0, 0, "Channel 1 Text" },
\r
309 { (COLORREF)0, 0, "Channel Text" },
\r
310 { (COLORREF)0, 0, "Kibitz Text" },
\r
311 { (COLORREF)0, 0, "Tell Text" },
\r
312 { (COLORREF)0, 0, "Challenge Text" },
\r
313 { (COLORREF)0, 0, "Request Text" },
\r
314 { (COLORREF)0, 0, "Seek Text" },
\r
315 { (COLORREF)0, 0, "Normal Text" },
\r
316 { (COLORREF)0, 0, "None" }
\r
321 static char *commentTitle;
\r
322 static char *commentText;
\r
323 static int commentIndex;
\r
324 static Boolean editComment = FALSE;
\r
325 HWND commentDialog = NULL;
\r
326 BOOLEAN commentDialogUp = FALSE;
\r
327 static int commentX, commentY, commentH, commentW;
\r
329 static char *analysisTitle;
\r
330 static char *analysisText;
\r
331 HWND analysisDialog = NULL;
\r
332 BOOLEAN analysisDialogUp = FALSE;
\r
333 static int analysisX, analysisY, analysisH, analysisW;
\r
335 char errorTitle[MSG_SIZ];
\r
336 char errorMessage[2*MSG_SIZ];
\r
337 HWND errorDialog = NULL;
\r
338 BOOLEAN moveErrorMessageUp = FALSE;
\r
339 BOOLEAN consoleEcho = TRUE;
\r
340 CHARFORMAT consoleCF;
\r
341 COLORREF consoleBackgroundColor;
\r
343 char *programVersion;
\r
349 typedef int CPKind;
\r
358 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
361 #define INPUT_SOURCE_BUF_SIZE 4096
\r
363 typedef struct _InputSource {
\r
370 char buf[INPUT_SOURCE_BUF_SIZE];
\r
374 InputCallback func;
\r
375 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
379 InputSource *consoleInputSource;
\r
384 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
385 VOID ConsoleCreate();
\r
387 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
389 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
390 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
392 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
393 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
394 void ParseIcsTextMenu(char *icsTextMenuString);
\r
395 VOID PopUpMoveDialog(char firstchar);
\r
396 VOID PopUpNameDialog(char firstchar);
\r
397 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
401 int GameListOptions();
\r
403 HWND moveHistoryDialog = NULL;
\r
404 BOOLEAN moveHistoryDialogUp = FALSE;
\r
406 WindowPlacement wpMoveHistory;
\r
408 HWND evalGraphDialog = NULL;
\r
409 BOOLEAN evalGraphDialogUp = FALSE;
\r
411 WindowPlacement wpEvalGraph;
\r
413 HWND engineOutputDialog = NULL;
\r
414 BOOLEAN engineOutputDialogUp = FALSE;
\r
416 WindowPlacement wpEngineOutput;
\r
418 VOID MoveHistoryPopUp();
\r
419 VOID MoveHistoryPopDown();
\r
420 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
421 BOOL MoveHistoryIsUp();
\r
423 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
424 VOID EvalGraphPopUp();
\r
425 VOID EvalGraphPopDown();
\r
426 BOOL EvalGraphIsUp();
\r
428 VOID EngineOutputPopUp();
\r
429 VOID EngineOutputPopDown();
\r
430 BOOL EngineOutputIsUp();
\r
431 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
433 VOID GothicPopUp(char *title, VariantClass variant);
\r
435 * Setting "frozen" should disable all user input other than deleting
\r
436 * the window. We do this while engines are initializing themselves.
\r
438 static int frozen = 0;
\r
439 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
445 if (frozen) return;
\r
447 hmenu = GetMenu(hwndMain);
\r
448 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
449 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
451 DrawMenuBar(hwndMain);
\r
454 /* Undo a FreezeUI */
\r
460 if (!frozen) return;
\r
462 hmenu = GetMenu(hwndMain);
\r
463 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
464 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
466 DrawMenuBar(hwndMain);
\r
469 /*---------------------------------------------------------------------------*\
\r
473 \*---------------------------------------------------------------------------*/
\r
476 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
477 LPSTR lpCmdLine, int nCmdShow)
\r
480 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
484 LoadLibrary("RICHED32.DLL");
\r
485 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
487 if (!InitApplication(hInstance)) {
\r
490 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
494 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
495 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
496 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
498 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
500 while (GetMessage(&msg, /* message structure */
\r
501 NULL, /* handle of window receiving the message */
\r
502 0, /* lowest message to examine */
\r
503 0)) /* highest message to examine */
\r
505 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
506 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
507 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
508 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
509 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
510 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
511 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
512 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
513 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
514 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
515 TranslateMessage(&msg); /* Translates virtual key codes */
\r
516 DispatchMessage(&msg); /* Dispatches message to window */
\r
521 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
524 /*---------------------------------------------------------------------------*\
\r
526 * Initialization functions
\r
528 \*---------------------------------------------------------------------------*/
\r
531 InitApplication(HINSTANCE hInstance)
\r
535 /* Fill in window class structure with parameters that describe the */
\r
538 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
539 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
540 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
541 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
542 wc.hInstance = hInstance; /* Owner of this class */
\r
543 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
544 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
545 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
546 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
547 wc.lpszClassName = szAppName; /* Name to register as */
\r
549 /* Register the window class and return success/failure code. */
\r
550 if (!RegisterClass(&wc)) return FALSE;
\r
552 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
553 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
555 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
556 wc.hInstance = hInstance;
\r
557 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
558 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
559 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
560 wc.lpszMenuName = NULL;
\r
561 wc.lpszClassName = szConsoleName;
\r
563 if (!RegisterClass(&wc)) return FALSE;
\r
568 /* Set by InitInstance, used by EnsureOnScreen */
\r
569 int screenHeight, screenWidth;
\r
572 EnsureOnScreen(int *x, int *y)
\r
574 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
575 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
576 if (*x > screenWidth - 32) *x = 0;
\r
577 if (*y > screenHeight - 32) *y = 0;
\r
578 if (*x < 0) *x = 0;
\r
579 if (*y < 0) *y = 0;
\r
580 // if (*x < 10) *x = 10;
\r
581 // if (*y < gap) *y = gap;
\r
585 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
587 HWND hwnd; /* Main window handle. */
\r
589 WINDOWPLACEMENT wp;
\r
592 hInst = hInstance; /* Store instance handle in our global variable */
\r
594 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
595 *filepart = NULLCHAR;
\r
597 GetCurrentDirectory(MSG_SIZ, installDir);
\r
599 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
600 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
601 if (appData.debugMode) {
\r
602 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
603 setbuf(debugFP, NULL);
\r
608 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
609 // InitEngineUCI( installDir, &second );
\r
611 /* Create a main window for this application instance. */
\r
612 hwnd = CreateWindow(szAppName, szTitle,
\r
613 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
614 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
615 NULL, NULL, hInstance, NULL);
\r
618 /* If window could not be created, return "failure" */
\r
623 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
624 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
625 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
627 if (first.programLogo == NULL && appData.debugMode) {
\r
628 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
630 } else if(appData.autoLogo) {
\r
631 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
633 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
634 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
638 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
639 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
641 if (second.programLogo == NULL && appData.debugMode) {
\r
642 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
644 } else if(appData.autoLogo) {
\r
645 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
647 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
648 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
652 iconWhite = LoadIcon(hInstance, "icon_white");
\r
653 iconBlack = LoadIcon(hInstance, "icon_black");
\r
654 iconCurrent = iconWhite;
\r
655 InitDrawingColors();
\r
656 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
657 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
658 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
659 /* Compute window size for each board size, and use the largest
\r
660 size that fits on this screen as the default. */
\r
661 InitDrawingSizes((BoardSize)ibs, 0);
\r
662 if (boardSize == (BoardSize)-1 &&
\r
663 winHeight <= screenHeight
\r
664 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
665 && winWidth <= screenWidth) {
\r
666 boardSize = (BoardSize)ibs;
\r
670 InitDrawingSizes(boardSize, 0);
\r
672 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
674 /* [AS] Load textures if specified */
\r
675 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
677 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
678 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
679 liteBackTextureMode = appData.liteBackTextureMode;
\r
681 if (liteBackTexture == NULL && appData.debugMode) {
\r
682 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
686 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
687 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
688 darkBackTextureMode = appData.darkBackTextureMode;
\r
690 if (darkBackTexture == NULL && appData.debugMode) {
\r
691 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
695 mysrandom( (unsigned) time(NULL) );
\r
697 /* [AS] Restore layout */
\r
698 if( wpMoveHistory.visible ) {
\r
699 MoveHistoryPopUp();
\r
702 if( wpEvalGraph.visible ) {
\r
706 if( wpEngineOutput.visible ) {
\r
707 EngineOutputPopUp();
\r
712 /* Make the window visible; update its client area; and return "success" */
\r
713 EnsureOnScreen(&boardX, &boardY);
\r
714 wp.length = sizeof(WINDOWPLACEMENT);
\r
716 wp.showCmd = nCmdShow;
\r
717 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
718 wp.rcNormalPosition.left = boardX;
\r
719 wp.rcNormalPosition.right = boardX + winWidth;
\r
720 wp.rcNormalPosition.top = boardY;
\r
721 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
722 SetWindowPlacement(hwndMain, &wp);
\r
724 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
725 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
728 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
729 if( gameInfo.variant != VariantFischeRandom ) {
\r
730 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
735 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
736 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
738 ShowWindow(hwndConsole, nCmdShow);
\r
740 UpdateWindow(hwnd);
\r
748 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
749 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
750 ArgSettingsFilename
\r
758 String *pString; // ArgString
\r
759 int *pInt; // ArgInt
\r
760 float *pFloat; // ArgFloat
\r
761 Boolean *pBoolean; // ArgBoolean
\r
762 COLORREF *pColor; // ArgColor
\r
763 ColorClass cc; // ArgAttribs
\r
764 String *pFilename; // ArgFilename
\r
765 BoardSize *pBoardSize; // ArgBoardSize
\r
766 int whichFont; // ArgFont
\r
767 DCB *pDCB; // ArgCommSettings
\r
768 String *pFilename; // ArgSettingsFilename
\r
776 ArgDescriptor argDescriptors[] = {
\r
777 /* positional arguments */
\r
778 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
779 { "", ArgNone, NULL },
\r
780 /* keyword arguments */
\r
781 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
782 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
783 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
784 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
785 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
786 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
787 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
788 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
789 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
790 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
791 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
792 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
793 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
794 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
795 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
796 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
797 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
798 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
800 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
802 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
804 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
805 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
807 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
808 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
809 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
810 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
811 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
812 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
813 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
814 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
815 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
816 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
817 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
818 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
819 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
820 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
821 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
822 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
823 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
824 /*!!bitmapDirectory?*/
\r
825 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
826 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
827 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
828 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
829 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
830 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
831 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
832 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
833 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
834 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
835 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
836 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
837 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
838 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
839 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
840 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
841 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
842 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
843 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
844 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
845 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
846 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
847 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
848 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
849 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
850 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
851 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
852 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
853 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
854 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
855 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
856 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
857 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
858 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
859 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
860 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
861 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
862 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
863 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
864 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
865 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
866 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
867 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
868 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
869 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
870 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
871 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
872 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
873 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
874 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
875 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
876 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
877 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
878 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
879 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
880 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
881 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
882 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
883 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
884 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
885 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
886 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
887 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
888 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
889 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
890 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
891 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
892 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
893 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
894 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
895 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
896 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
897 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
898 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
899 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
900 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
901 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
902 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
903 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
904 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
905 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
906 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
907 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
908 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
909 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
910 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
911 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
912 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
913 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
914 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
915 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
916 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
917 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
918 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
919 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
920 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
921 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
922 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
923 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
924 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
925 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
926 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
927 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
928 TRUE }, /* must come after all fonts */
\r
929 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
930 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
931 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
932 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
933 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
934 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
935 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
936 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
937 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
938 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
939 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
940 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
941 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
942 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
943 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
944 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
945 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
946 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
947 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
948 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
949 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
950 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
951 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
952 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
953 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
954 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
955 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
956 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
957 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
958 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
959 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
961 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
962 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
964 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
965 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
966 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
967 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
968 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
969 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
970 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
971 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
972 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
973 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
974 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
975 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
976 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
977 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
978 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
979 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
980 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
981 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
982 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
983 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
984 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
985 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
986 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
987 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
988 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
989 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
990 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
991 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
992 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
993 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
994 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
995 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
996 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
997 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
998 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
999 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1000 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1001 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1002 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1003 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1004 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1005 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1006 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1007 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1008 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1009 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1010 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1011 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1012 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1013 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1014 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1015 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1016 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1017 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1018 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1019 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1020 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1021 { "highlightLastMove", ArgBoolean,
\r
1022 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1023 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1024 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1025 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1026 { "highlightDragging", ArgBoolean,
\r
1027 (LPVOID) &appData.highlightDragging, TRUE },
\r
1028 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1029 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1030 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1031 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1032 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1033 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1034 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1035 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1036 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1037 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1038 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1039 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1040 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1041 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1042 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1043 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1044 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1045 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1046 { "soundShout", ArgFilename,
\r
1047 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1048 { "soundSShout", ArgFilename,
\r
1049 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1050 { "soundChannel1", ArgFilename,
\r
1051 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1052 { "soundChannel", ArgFilename,
\r
1053 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1054 { "soundKibitz", ArgFilename,
\r
1055 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1056 { "soundTell", ArgFilename,
\r
1057 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1058 { "soundChallenge", ArgFilename,
\r
1059 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1060 { "soundRequest", ArgFilename,
\r
1061 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1062 { "soundSeek", ArgFilename,
\r
1063 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1064 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1065 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1066 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1067 { "soundIcsLoss", ArgFilename,
\r
1068 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1069 { "soundIcsDraw", ArgFilename,
\r
1070 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1071 { "soundIcsUnfinished", ArgFilename,
\r
1072 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1073 { "soundIcsAlarm", ArgFilename,
\r
1074 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1075 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1076 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1077 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1078 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1079 { "reuseChessPrograms", ArgBoolean,
\r
1080 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1081 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1082 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1083 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1084 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1085 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1086 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1087 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1088 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1089 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1090 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1091 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1092 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1093 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1094 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1095 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1096 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1097 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1098 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1099 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1100 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1101 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1102 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1103 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1104 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1105 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1106 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1107 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1108 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1109 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1110 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1111 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1112 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1113 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1114 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1115 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1116 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1117 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1119 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1121 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1122 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1123 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1124 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1125 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1126 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1127 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1128 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1129 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1130 /* [AS] New features */
\r
1131 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1132 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1133 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1134 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1135 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1136 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1137 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1138 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1139 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1140 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1141 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1142 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1143 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1144 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1145 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1146 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1147 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1148 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1149 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1150 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1151 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1152 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1153 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1154 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1155 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1156 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1157 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1158 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1159 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1160 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1161 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1162 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1163 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1164 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1165 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1166 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1167 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1168 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1169 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1170 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1171 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1172 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1173 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1174 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1175 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1176 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1177 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1178 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1179 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1180 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1182 /* [AS] Layout stuff */
\r
1183 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1184 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1185 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1186 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1187 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1189 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1190 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1191 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1192 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1193 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1195 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1196 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1197 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1198 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1199 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1201 /* [HGM] board-size, adjudication and misc. options */
\r
1202 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1203 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1204 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1205 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1206 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1207 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1208 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1209 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1210 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1211 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1212 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1213 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1214 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1215 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1216 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1217 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1218 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1219 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1220 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1221 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1222 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1223 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1224 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1225 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1226 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1227 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1228 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1229 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1230 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1233 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1234 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1235 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1236 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1237 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1238 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1239 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1240 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1241 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1242 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1243 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1244 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1245 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1247 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1248 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1249 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1250 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1251 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1252 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1253 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1255 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1256 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1257 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1258 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1259 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1260 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1261 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1262 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1263 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1264 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1265 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1266 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1267 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1268 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1269 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1270 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1271 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1272 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1274 /* [HGM] options for broadcasting and time odds */
\r
1275 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1276 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1277 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1278 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1279 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1280 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1281 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1282 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1283 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1284 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1285 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1286 { NULL, ArgNone, NULL, FALSE }
\r
1290 /* Kludge for indirection files on command line */
\r
1291 char* lastIndirectionFilename;
\r
1292 ArgDescriptor argDescriptorIndirection =
\r
1293 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1297 ExitArgError(char *msg, char *badArg)
\r
1299 char buf[MSG_SIZ];
\r
1301 sprintf(buf, "%s %s", msg, badArg);
\r
1302 DisplayFatalError(buf, 0, 2);
\r
1306 /* Command line font name parser. NULL name means do nothing.
\r
1307 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1308 For backward compatibility, syntax without the colon is also
\r
1309 accepted, but font names with digits in them won't work in that case.
\r
1312 ParseFontName(char *name, MyFontParams *mfp)
\r
1315 if (name == NULL) return;
\r
1317 q = strchr(p, ':');
\r
1319 if (q - p >= sizeof(mfp->faceName))
\r
1320 ExitArgError("Font name too long:", name);
\r
1321 memcpy(mfp->faceName, p, q - p);
\r
1322 mfp->faceName[q - p] = NULLCHAR;
\r
1325 q = mfp->faceName;
\r
1326 while (*p && !isdigit(*p)) {
\r
1328 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1329 ExitArgError("Font name too long:", name);
\r
1331 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1334 if (!*p) ExitArgError("Font point size missing:", name);
\r
1335 mfp->pointSize = (float) atof(p);
\r
1336 mfp->bold = (strchr(p, 'b') != NULL);
\r
1337 mfp->italic = (strchr(p, 'i') != NULL);
\r
1338 mfp->underline = (strchr(p, 'u') != NULL);
\r
1339 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1342 /* Color name parser.
\r
1343 X version accepts X color names, but this one
\r
1344 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1346 ParseColorName(char *name)
\r
1348 int red, green, blue, count;
\r
1349 char buf[MSG_SIZ];
\r
1351 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1353 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1354 &red, &green, &blue);
\r
1357 sprintf(buf, "Can't parse color name %s", name);
\r
1358 DisplayError(buf, 0);
\r
1359 return RGB(0, 0, 0);
\r
1361 return PALETTERGB(red, green, blue);
\r
1365 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1367 char *e = argValue;
\r
1371 if (*e == 'b') eff |= CFE_BOLD;
\r
1372 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1373 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1374 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1375 else if (*e == '#' || isdigit(*e)) break;
\r
1379 *color = ParseColorName(e);
\r
1384 ParseBoardSize(char *name)
\r
1386 BoardSize bs = SizeTiny;
\r
1387 while (sizeInfo[bs].name != NULL) {
\r
1388 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1391 ExitArgError("Unrecognized board size value", name);
\r
1392 return bs; /* not reached */
\r
1397 StringGet(void *getClosure)
\r
1399 char **p = (char **) getClosure;
\r
1404 FileGet(void *getClosure)
\r
1407 FILE* f = (FILE*) getClosure;
\r
1416 /* Parse settings file named "name". If file found, return the
\r
1417 full name in fullname and return TRUE; else return FALSE */
\r
1419 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1424 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1425 f = fopen(fullname, "r");
\r
1427 ParseArgs(FileGet, f);
\r
1436 ParseArgs(GetFunc get, void *cl)
\r
1438 char argName[ARG_MAX];
\r
1439 char argValue[ARG_MAX];
\r
1440 ArgDescriptor *ad;
\r
1449 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1450 if (ch == NULLCHAR) break;
\r
1452 /* Comment to end of line */
\r
1454 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1456 } else if (ch == '/' || ch == '-') {
\r
1459 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1460 ch != '\n' && ch != '\t') {
\r
1466 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1467 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1469 if (ad->argName == NULL)
\r
1470 ExitArgError("Unrecognized argument", argName);
\r
1472 } else if (ch == '@') {
\r
1473 /* Indirection file */
\r
1474 ad = &argDescriptorIndirection;
\r
1477 /* Positional argument */
\r
1478 ad = &argDescriptors[posarg++];
\r
1479 strcpy(argName, ad->argName);
\r
1482 if (ad->argType == ArgTrue) {
\r
1483 *(Boolean *) ad->argLoc = TRUE;
\r
1486 if (ad->argType == ArgFalse) {
\r
1487 *(Boolean *) ad->argLoc = FALSE;
\r
1491 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1492 if (ch == NULLCHAR || ch == '\n') {
\r
1493 ExitArgError("No value provided for argument", argName);
\r
1497 // Quoting with { }. No characters have to (or can) be escaped.
\r
1498 // Thus the string cannot contain a '}' character.
\r
1518 } else if (ch == '\'' || ch == '"') {
\r
1519 // Quoting with ' ' or " ", with \ as escape character.
\r
1520 // Inconvenient for long strings that may contain Windows filenames.
\r
1537 if (ch == start) {
\r
1546 if (ad->argType == ArgFilename
\r
1547 || ad->argType == ArgSettingsFilename) {
\r
1553 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1577 for (i = 0; i < 3; i++) {
\r
1578 if (ch >= '0' && ch <= '7') {
\r
1579 octval = octval*8 + (ch - '0');
\r
1586 *q++ = (char) octval;
\r
1597 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1604 switch (ad->argType) {
\r
1606 *(int *) ad->argLoc = atoi(argValue);
\r
1610 *(float *) ad->argLoc = (float) atof(argValue);
\r
1615 *(char **) ad->argLoc = strdup(argValue);
\r
1618 case ArgSettingsFilename:
\r
1620 char fullname[MSG_SIZ];
\r
1621 if (ParseSettingsFile(argValue, fullname)) {
\r
1622 if (ad->argLoc != NULL) {
\r
1623 *(char **) ad->argLoc = strdup(fullname);
\r
1626 if (ad->argLoc != NULL) {
\r
1628 ExitArgError("Failed to open indirection file", argValue);
\r
1635 switch (argValue[0]) {
\r
1638 *(Boolean *) ad->argLoc = TRUE;
\r
1642 *(Boolean *) ad->argLoc = FALSE;
\r
1645 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1651 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1654 case ArgAttribs: {
\r
1655 ColorClass cc = (ColorClass)ad->argLoc;
\r
1656 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1660 case ArgBoardSize:
\r
1661 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1665 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1668 case ArgCommSettings:
\r
1669 ParseCommSettings(argValue, &dcb);
\r
1673 ExitArgError("Unrecognized argument", argValue);
\r
1682 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1684 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1685 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1688 lf->lfEscapement = 0;
\r
1689 lf->lfOrientation = 0;
\r
1690 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1691 lf->lfItalic = mfp->italic;
\r
1692 lf->lfUnderline = mfp->underline;
\r
1693 lf->lfStrikeOut = mfp->strikeout;
\r
1694 lf->lfCharSet = DEFAULT_CHARSET;
\r
1695 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1696 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1697 lf->lfQuality = DEFAULT_QUALITY;
\r
1698 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1699 strcpy(lf->lfFaceName, mfp->faceName);
\r
1703 CreateFontInMF(MyFont *mf)
\r
1705 LFfromMFP(&mf->lf, &mf->mfp);
\r
1706 if (mf->hf) DeleteObject(mf->hf);
\r
1707 mf->hf = CreateFontIndirect(&mf->lf);
\r
1711 SetDefaultTextAttribs()
\r
1714 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1715 ParseAttribs(&textAttribs[cc].color,
\r
1716 &textAttribs[cc].effects,
\r
1717 defaultTextAttribs[cc]);
\r
1722 SetDefaultSounds()
\r
1726 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1727 textAttribs[cc].sound.name = strdup("");
\r
1728 textAttribs[cc].sound.data = NULL;
\r
1730 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1731 sounds[sc].name = strdup("");
\r
1732 sounds[sc].data = NULL;
\r
1734 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1742 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1743 MyLoadSound(&textAttribs[cc].sound);
\r
1745 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1746 MyLoadSound(&sounds[sc]);
\r
1751 InitAppData(LPSTR lpCmdLine)
\r
1754 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1757 programName = szAppName;
\r
1759 /* Initialize to defaults */
\r
1760 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1761 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1762 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1763 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1764 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1765 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1766 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1767 SetDefaultTextAttribs();
\r
1768 SetDefaultSounds();
\r
1769 appData.movesPerSession = MOVES_PER_SESSION;
\r
1770 appData.initString = INIT_STRING;
\r
1771 appData.secondInitString = INIT_STRING;
\r
1772 appData.firstComputerString = COMPUTER_STRING;
\r
1773 appData.secondComputerString = COMPUTER_STRING;
\r
1774 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1775 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1776 appData.firstPlaysBlack = FALSE;
\r
1777 appData.noChessProgram = FALSE;
\r
1778 chessProgram = FALSE;
\r
1779 appData.firstHost = FIRST_HOST;
\r
1780 appData.secondHost = SECOND_HOST;
\r
1781 appData.firstDirectory = FIRST_DIRECTORY;
\r
1782 appData.secondDirectory = SECOND_DIRECTORY;
\r
1783 appData.bitmapDirectory = "";
\r
1784 appData.remoteShell = REMOTE_SHELL;
\r
1785 appData.remoteUser = "";
\r
1786 appData.timeDelay = TIME_DELAY;
\r
1787 appData.timeControl = TIME_CONTROL;
\r
1788 appData.timeIncrement = TIME_INCREMENT;
\r
1789 appData.icsActive = FALSE;
\r
1790 appData.icsHost = "";
\r
1791 appData.icsPort = ICS_PORT;
\r
1792 appData.icsCommPort = ICS_COMM_PORT;
\r
1793 appData.icsLogon = ICS_LOGON;
\r
1794 appData.icsHelper = "";
\r
1795 appData.useTelnet = FALSE;
\r
1796 appData.telnetProgram = TELNET_PROGRAM;
\r
1797 appData.gateway = "";
\r
1798 appData.loadGameFile = "";
\r
1799 appData.loadGameIndex = 0;
\r
1800 appData.saveGameFile = "";
\r
1801 appData.autoSaveGames = FALSE;
\r
1802 appData.loadPositionFile = "";
\r
1803 appData.loadPositionIndex = 1;
\r
1804 appData.savePositionFile = "";
\r
1805 appData.matchMode = FALSE;
\r
1806 appData.matchGames = 0;
\r
1807 appData.monoMode = FALSE;
\r
1808 appData.debugMode = FALSE;
\r
1809 appData.clockMode = TRUE;
\r
1810 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1811 appData.Iconic = FALSE; /*unused*/
\r
1812 appData.searchTime = "";
\r
1813 appData.searchDepth = 0;
\r
1814 appData.showCoords = FALSE;
\r
1815 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1816 appData.autoCallFlag = FALSE;
\r
1817 appData.flipView = FALSE;
\r
1818 appData.autoFlipView = TRUE;
\r
1819 appData.cmailGameName = "";
\r
1820 appData.alwaysPromoteToQueen = FALSE;
\r
1821 appData.oldSaveStyle = FALSE;
\r
1822 appData.quietPlay = FALSE;
\r
1823 appData.showThinking = FALSE;
\r
1824 appData.ponderNextMove = TRUE;
\r
1825 appData.periodicUpdates = TRUE;
\r
1826 appData.popupExitMessage = TRUE;
\r
1827 appData.popupMoveErrors = FALSE;
\r
1828 appData.autoObserve = FALSE;
\r
1829 appData.autoComment = FALSE;
\r
1830 appData.animate = TRUE;
\r
1831 appData.animSpeed = 10;
\r
1832 appData.animateDragging = TRUE;
\r
1833 appData.highlightLastMove = TRUE;
\r
1834 appData.getMoveList = TRUE;
\r
1835 appData.testLegality = TRUE;
\r
1836 appData.premove = TRUE;
\r
1837 appData.premoveWhite = FALSE;
\r
1838 appData.premoveWhiteText = "";
\r
1839 appData.premoveBlack = FALSE;
\r
1840 appData.premoveBlackText = "";
\r
1841 appData.icsAlarm = TRUE;
\r
1842 appData.icsAlarmTime = 5000;
\r
1843 appData.autoRaiseBoard = TRUE;
\r
1844 appData.localLineEditing = TRUE;
\r
1845 appData.colorize = TRUE;
\r
1846 appData.reuseFirst = TRUE;
\r
1847 appData.reuseSecond = TRUE;
\r
1848 appData.blindfold = FALSE;
\r
1849 appData.icsEngineAnalyze = FALSE;
\r
1850 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1851 dcb.DCBlength = sizeof(DCB);
\r
1852 dcb.BaudRate = 9600;
\r
1853 dcb.fBinary = TRUE;
\r
1854 dcb.fParity = FALSE;
\r
1855 dcb.fOutxCtsFlow = FALSE;
\r
1856 dcb.fOutxDsrFlow = FALSE;
\r
1857 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1858 dcb.fDsrSensitivity = FALSE;
\r
1859 dcb.fTXContinueOnXoff = TRUE;
\r
1860 dcb.fOutX = FALSE;
\r
1862 dcb.fNull = FALSE;
\r
1863 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1864 dcb.fAbortOnError = FALSE;
\r
1865 /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */
\r
1866 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
\r
1867 //dcb.wReserved = 0;
\r
1869 dcb.wReserved = 0;
\r
1872 dcb.Parity = SPACEPARITY;
\r
1873 dcb.StopBits = ONESTOPBIT;
\r
1874 settingsFileName = SETTINGS_FILE;
\r
1875 saveSettingsOnExit = TRUE;
\r
1876 boardX = CW_USEDEFAULT;
\r
1877 boardY = CW_USEDEFAULT;
\r
1878 consoleX = CW_USEDEFAULT;
\r
1879 consoleY = CW_USEDEFAULT;
\r
1880 consoleW = CW_USEDEFAULT;
\r
1881 consoleH = CW_USEDEFAULT;
\r
1882 analysisX = CW_USEDEFAULT;
\r
1883 analysisY = CW_USEDEFAULT;
\r
1884 analysisW = CW_USEDEFAULT;
\r
1885 analysisH = CW_USEDEFAULT;
\r
1886 commentX = CW_USEDEFAULT;
\r
1887 commentY = CW_USEDEFAULT;
\r
1888 commentW = CW_USEDEFAULT;
\r
1889 commentH = CW_USEDEFAULT;
\r
1890 editTagsX = CW_USEDEFAULT;
\r
1891 editTagsY = CW_USEDEFAULT;
\r
1892 editTagsW = CW_USEDEFAULT;
\r
1893 editTagsH = CW_USEDEFAULT;
\r
1894 gameListX = CW_USEDEFAULT;
\r
1895 gameListY = CW_USEDEFAULT;
\r
1896 gameListW = CW_USEDEFAULT;
\r
1897 gameListH = CW_USEDEFAULT;
\r
1898 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1899 icsNames = ICS_NAMES;
\r
1900 firstChessProgramNames = FCP_NAMES;
\r
1901 secondChessProgramNames = SCP_NAMES;
\r
1902 appData.initialMode = "";
\r
1903 appData.variant = "normal";
\r
1904 appData.firstProtocolVersion = PROTOVER;
\r
1905 appData.secondProtocolVersion = PROTOVER;
\r
1906 appData.showButtonBar = TRUE;
\r
1908 /* [AS] New properties (see comments in header file) */
\r
1909 appData.firstScoreIsAbsolute = FALSE;
\r
1910 appData.secondScoreIsAbsolute = FALSE;
\r
1911 appData.saveExtendedInfoInPGN = FALSE;
\r
1912 appData.hideThinkingFromHuman = FALSE;
\r
1913 appData.liteBackTextureFile = "";
\r
1914 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1915 appData.darkBackTextureFile = "";
\r
1916 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1917 appData.renderPiecesWithFont = "";
\r
1918 appData.fontToPieceTable = "";
\r
1919 appData.fontBackColorWhite = 0;
\r
1920 appData.fontForeColorWhite = 0;
\r
1921 appData.fontBackColorBlack = 0;
\r
1922 appData.fontForeColorBlack = 0;
\r
1923 appData.fontPieceSize = 80;
\r
1924 appData.overrideLineGap = 1;
\r
1925 appData.adjudicateLossThreshold = 0;
\r
1926 appData.delayBeforeQuit = 0;
\r
1927 appData.delayAfterQuit = 0;
\r
1928 appData.nameOfDebugFile = "winboard.debug";
\r
1929 appData.pgnEventHeader = "Computer Chess Game";
\r
1930 appData.defaultFrcPosition = -1;
\r
1931 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1932 appData.saveOutOfBookInfo = TRUE;
\r
1933 appData.showEvalInMoveHistory = TRUE;
\r
1934 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1935 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1936 appData.highlightMoveWithArrow = FALSE;
\r
1937 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1938 appData.useStickyWindows = TRUE;
\r
1939 appData.adjudicateDrawMoves = 0;
\r
1940 appData.autoDisplayComment = TRUE;
\r
1941 appData.autoDisplayTags = TRUE;
\r
1942 appData.firstIsUCI = FALSE;
\r
1943 appData.secondIsUCI = FALSE;
\r
1944 appData.firstHasOwnBookUCI = TRUE;
\r
1945 appData.secondHasOwnBookUCI = TRUE;
\r
1946 appData.polyglotDir = "";
\r
1947 appData.usePolyglotBook = FALSE;
\r
1948 appData.polyglotBook = "";
\r
1949 appData.defaultHashSize = 64;
\r
1950 appData.defaultCacheSizeEGTB = 4;
\r
1951 appData.defaultPathEGTB = "c:\\egtb";
\r
1952 appData.firstOptions = "";
\r
1953 appData.secondOptions = "";
\r
1955 InitWindowPlacement( &wpMoveHistory );
\r
1956 InitWindowPlacement( &wpEvalGraph );
\r
1957 InitWindowPlacement( &wpEngineOutput );
\r
1959 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1960 appData.NrFiles = -1;
\r
1961 appData.NrRanks = -1;
\r
1962 appData.holdingsSize = -1;
\r
1963 appData.testClaims = FALSE;
\r
1964 appData.checkMates = FALSE;
\r
1965 appData.materialDraws= FALSE;
\r
1966 appData.trivialDraws = FALSE;
\r
1967 appData.ruleMoves = 51;
\r
1968 appData.drawRepeats = 6;
\r
1969 appData.matchPause = 10000;
\r
1970 appData.alphaRank = FALSE;
\r
1971 appData.allWhite = FALSE;
\r
1972 appData.upsideDown = FALSE;
\r
1973 appData.serverPause = 15;
\r
1974 appData.serverMovesName = NULL;
\r
1975 appData.suppressLoadMoves = FALSE;
\r
1976 appData.firstTimeOdds = 1;
\r
1977 appData.secondTimeOdds = 1;
\r
1978 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1979 appData.secondAccumulateTC = 1;
\r
1980 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1981 appData.secondNPS = -1;
\r
1982 appData.engineComments = 1;
\r
1983 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1984 appData.egtFormats = "";
\r
1987 appData.zippyTalk = ZIPPY_TALK;
\r
1988 appData.zippyPlay = ZIPPY_PLAY;
\r
1989 appData.zippyLines = ZIPPY_LINES;
\r
1990 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1991 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1992 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1993 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1994 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1995 appData.zippyUseI = ZIPPY_USE_I;
\r
1996 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1997 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1998 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1999 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2000 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2001 appData.zippyAbort = ZIPPY_ABORT;
\r
2002 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2003 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2004 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2007 /* Point font array elements to structures and
\r
2008 parse default font names */
\r
2009 for (i=0; i<NUM_FONTS; i++) {
\r
2010 for (j=0; j<NUM_SIZES; j++) {
\r
2011 font[j][i] = &fontRec[j][i];
\r
2012 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2016 /* Parse default settings file if any */
\r
2017 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2018 settingsFileName = strdup(buf);
\r
2021 /* Parse command line */
\r
2022 ParseArgs(StringGet, &lpCmdLine);
\r
2024 /* [HGM] make sure board size is acceptable */
\r
2025 if(appData.NrFiles > BOARD_SIZE ||
\r
2026 appData.NrRanks > BOARD_SIZE )
\r
2027 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2029 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2030 * with options from the command line, we now make an even higher priority
\r
2031 * overrule by WB options attached to the engine command line. This so that
\r
2032 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2035 if(appData.firstChessProgram != NULL) {
\r
2036 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2037 static char *f = "first";
\r
2038 char buf[MSG_SIZ], *q = buf;
\r
2039 if(p != NULL) { // engine command line contains WinBoard options
\r
2040 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2041 ParseArgs(StringGet, &q);
\r
2042 p[-1] = 0; // cut them offengine command line
\r
2045 // now do same for second chess program
\r
2046 if(appData.secondChessProgram != NULL) {
\r
2047 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2048 static char *s = "second";
\r
2049 char buf[MSG_SIZ], *q = buf;
\r
2050 if(p != NULL) { // engine command line contains WinBoard options
\r
2051 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2052 ParseArgs(StringGet, &q);
\r
2053 p[-1] = 0; // cut them offengine command line
\r
2058 /* Propagate options that affect others */
\r
2059 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2060 if (appData.icsActive || appData.noChessProgram) {
\r
2061 chessProgram = FALSE; /* not local chess program mode */
\r
2064 /* Open startup dialog if needed */
\r
2065 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2066 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2067 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2068 *appData.secondChessProgram == NULLCHAR))) {
\r
2071 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2072 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2073 FreeProcInstance(lpProc);
\r
2076 /* Make sure save files land in the right (?) directory */
\r
2077 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2078 appData.saveGameFile = strdup(buf);
\r
2080 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2081 appData.savePositionFile = strdup(buf);
\r
2084 /* Finish initialization for fonts and sounds */
\r
2085 for (i=0; i<NUM_FONTS; i++) {
\r
2086 for (j=0; j<NUM_SIZES; j++) {
\r
2087 CreateFontInMF(font[j][i]);
\r
2090 /* xboard, and older WinBoards, controlled the move sound with the
\r
2091 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2092 always turn the option on (so that the backend will call us),
\r
2093 then let the user turn the sound off by setting it to silence if
\r
2094 desired. To accommodate old winboard.ini files saved by old
\r
2095 versions of WinBoard, we also turn off the sound if the option
\r
2096 was initially set to false. */
\r
2097 if (!appData.ringBellAfterMoves) {
\r
2098 sounds[(int)SoundMove].name = strdup("");
\r
2099 appData.ringBellAfterMoves = TRUE;
\r
2101 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2102 SetCurrentDirectory(installDir);
\r
2104 SetCurrentDirectory(currDir);
\r
2106 p = icsTextMenuString;
\r
2107 if (p[0] == '@') {
\r
2108 FILE* f = fopen(p + 1, "r");
\r
2110 DisplayFatalError(p + 1, errno, 2);
\r
2113 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2115 buf[i] = NULLCHAR;
\r
2118 ParseIcsTextMenu(strdup(p));
\r
2125 HMENU hmenu = GetMenu(hwndMain);
\r
2127 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2128 MF_BYCOMMAND|((appData.icsActive &&
\r
2129 *appData.icsCommPort != NULLCHAR) ?
\r
2130 MF_ENABLED : MF_GRAYED));
\r
2131 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2132 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2133 MF_CHECKED : MF_UNCHECKED));
\r
2138 SaveSettings(char* name)
\r
2141 ArgDescriptor *ad;
\r
2142 WINDOWPLACEMENT wp;
\r
2143 char dir[MSG_SIZ];
\r
2145 if (!hwndMain) return;
\r
2147 GetCurrentDirectory(MSG_SIZ, dir);
\r
2148 SetCurrentDirectory(installDir);
\r
2149 f = fopen(name, "w");
\r
2150 SetCurrentDirectory(dir);
\r
2152 DisplayError(name, errno);
\r
2155 fprintf(f, ";\n");
\r
2156 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2157 fprintf(f, ";\n");
\r
2158 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2159 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2160 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2161 fprintf(f, ";\n");
\r
2163 wp.length = sizeof(WINDOWPLACEMENT);
\r
2164 GetWindowPlacement(hwndMain, &wp);
\r
2165 boardX = wp.rcNormalPosition.left;
\r
2166 boardY = wp.rcNormalPosition.top;
\r
2168 if (hwndConsole) {
\r
2169 GetWindowPlacement(hwndConsole, &wp);
\r
2170 consoleX = wp.rcNormalPosition.left;
\r
2171 consoleY = wp.rcNormalPosition.top;
\r
2172 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2173 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2176 if (analysisDialog) {
\r
2177 GetWindowPlacement(analysisDialog, &wp);
\r
2178 analysisX = wp.rcNormalPosition.left;
\r
2179 analysisY = wp.rcNormalPosition.top;
\r
2180 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2181 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2184 if (commentDialog) {
\r
2185 GetWindowPlacement(commentDialog, &wp);
\r
2186 commentX = wp.rcNormalPosition.left;
\r
2187 commentY = wp.rcNormalPosition.top;
\r
2188 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2189 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2192 if (editTagsDialog) {
\r
2193 GetWindowPlacement(editTagsDialog, &wp);
\r
2194 editTagsX = wp.rcNormalPosition.left;
\r
2195 editTagsY = wp.rcNormalPosition.top;
\r
2196 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2197 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2200 if (gameListDialog) {
\r
2201 GetWindowPlacement(gameListDialog, &wp);
\r
2202 gameListX = wp.rcNormalPosition.left;
\r
2203 gameListY = wp.rcNormalPosition.top;
\r
2204 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2205 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2208 /* [AS] Move history */
\r
2209 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2211 if( moveHistoryDialog ) {
\r
2212 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2213 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2214 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2215 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2216 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2219 /* [AS] Eval graph */
\r
2220 wpEvalGraph.visible = EvalGraphIsUp();
\r
2222 if( evalGraphDialog ) {
\r
2223 GetWindowPlacement(evalGraphDialog, &wp);
\r
2224 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2225 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2226 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2227 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2230 /* [AS] Engine output */
\r
2231 wpEngineOutput.visible = EngineOutputIsUp();
\r
2233 if( engineOutputDialog ) {
\r
2234 GetWindowPlacement(engineOutputDialog, &wp);
\r
2235 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2236 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2237 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2238 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2241 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2242 if (!ad->save) continue;
\r
2243 switch (ad->argType) {
\r
2246 char *p = *(char **)ad->argLoc;
\r
2247 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2248 /* Quote multiline values or \-containing values
\r
2249 with { } if possible */
\r
2250 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2252 /* Else quote with " " */
\r
2253 fprintf(f, "/%s=\"", ad->argName);
\r
2255 if (*p == '\n') fprintf(f, "\n");
\r
2256 else if (*p == '\r') fprintf(f, "\\r");
\r
2257 else if (*p == '\t') fprintf(f, "\\t");
\r
2258 else if (*p == '\b') fprintf(f, "\\b");
\r
2259 else if (*p == '\f') fprintf(f, "\\f");
\r
2260 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2261 else if (*p == '\"') fprintf(f, "\\\"");
\r
2262 else if (*p == '\\') fprintf(f, "\\\\");
\r
2266 fprintf(f, "\"\n");
\r
2271 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2274 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2277 fprintf(f, "/%s=%s\n", ad->argName,
\r
2278 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2281 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2284 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2288 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2289 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2290 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2295 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2296 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2297 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2298 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2299 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2300 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2301 (ta->effects) ? " " : "",
\r
2302 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2306 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2307 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2309 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2312 case ArgBoardSize:
\r
2313 fprintf(f, "/%s=%s\n", ad->argName,
\r
2314 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2319 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2320 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2321 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2322 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2323 ad->argName, mfp->faceName, mfp->pointSize,
\r
2324 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2325 mfp->bold ? "b" : "",
\r
2326 mfp->italic ? "i" : "",
\r
2327 mfp->underline ? "u" : "",
\r
2328 mfp->strikeout ? "s" : "");
\r
2332 case ArgCommSettings:
\r
2333 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2341 /*---------------------------------------------------------------------------*\
\r
2343 * GDI board drawing routines
\r
2345 \*---------------------------------------------------------------------------*/
\r
2347 /* [AS] Draw square using background texture */
\r
2348 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2353 return; /* Should never happen! */
\r
2356 SetGraphicsMode( dst, GM_ADVANCED );
\r
2363 /* X reflection */
\r
2368 x.eDx = (FLOAT) dw + dx - 1;
\r
2371 SetWorldTransform( dst, &x );
\r
2374 /* Y reflection */
\r
2380 x.eDy = (FLOAT) dh + dy - 1;
\r
2382 SetWorldTransform( dst, &x );
\r
2390 x.eDx = (FLOAT) dx;
\r
2391 x.eDy = (FLOAT) dy;
\r
2394 SetWorldTransform( dst, &x );
\r
2398 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2406 SetWorldTransform( dst, &x );
\r
2408 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2411 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2413 PM_WP = (int) WhitePawn,
\r
2414 PM_WN = (int) WhiteKnight,
\r
2415 PM_WB = (int) WhiteBishop,
\r
2416 PM_WR = (int) WhiteRook,
\r
2417 PM_WQ = (int) WhiteQueen,
\r
2418 PM_WF = (int) WhiteFerz,
\r
2419 PM_WW = (int) WhiteWazir,
\r
2420 PM_WE = (int) WhiteAlfil,
\r
2421 PM_WM = (int) WhiteMan,
\r
2422 PM_WO = (int) WhiteCannon,
\r
2423 PM_WU = (int) WhiteUnicorn,
\r
2424 PM_WH = (int) WhiteNightrider,
\r
2425 PM_WA = (int) WhiteAngel,
\r
2426 PM_WC = (int) WhiteMarshall,
\r
2427 PM_WAB = (int) WhiteCardinal,
\r
2428 PM_WD = (int) WhiteDragon,
\r
2429 PM_WL = (int) WhiteLance,
\r
2430 PM_WS = (int) WhiteCobra,
\r
2431 PM_WV = (int) WhiteFalcon,
\r
2432 PM_WSG = (int) WhiteSilver,
\r
2433 PM_WG = (int) WhiteGrasshopper,
\r
2434 PM_WK = (int) WhiteKing,
\r
2435 PM_BP = (int) BlackPawn,
\r
2436 PM_BN = (int) BlackKnight,
\r
2437 PM_BB = (int) BlackBishop,
\r
2438 PM_BR = (int) BlackRook,
\r
2439 PM_BQ = (int) BlackQueen,
\r
2440 PM_BF = (int) BlackFerz,
\r
2441 PM_BW = (int) BlackWazir,
\r
2442 PM_BE = (int) BlackAlfil,
\r
2443 PM_BM = (int) BlackMan,
\r
2444 PM_BO = (int) BlackCannon,
\r
2445 PM_BU = (int) BlackUnicorn,
\r
2446 PM_BH = (int) BlackNightrider,
\r
2447 PM_BA = (int) BlackAngel,
\r
2448 PM_BC = (int) BlackMarshall,
\r
2449 PM_BG = (int) BlackGrasshopper,
\r
2450 PM_BAB = (int) BlackCardinal,
\r
2451 PM_BD = (int) BlackDragon,
\r
2452 PM_BL = (int) BlackLance,
\r
2453 PM_BS = (int) BlackCobra,
\r
2454 PM_BV = (int) BlackFalcon,
\r
2455 PM_BSG = (int) BlackSilver,
\r
2456 PM_BK = (int) BlackKing
\r
2459 static HFONT hPieceFont = NULL;
\r
2460 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2461 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2462 static int fontBitmapSquareSize = 0;
\r
2463 static char pieceToFontChar[(int) EmptySquare] =
\r
2464 { 'p', 'n', 'b', 'r', 'q',
\r
2465 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2466 'k', 'o', 'm', 'v', 't', 'w',
\r
2467 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2470 extern BOOL SetCharTable( char *table, const char * map );
\r
2471 /* [HGM] moved to backend.c */
\r
2473 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2476 BYTE r1 = GetRValue( color );
\r
2477 BYTE g1 = GetGValue( color );
\r
2478 BYTE b1 = GetBValue( color );
\r
2484 /* Create a uniform background first */
\r
2485 hbrush = CreateSolidBrush( color );
\r
2486 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2487 FillRect( hdc, &rc, hbrush );
\r
2488 DeleteObject( hbrush );
\r
2491 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2492 int steps = squareSize / 2;
\r
2495 for( i=0; i<steps; i++ ) {
\r
2496 BYTE r = r1 - (r1-r2) * i / steps;
\r
2497 BYTE g = g1 - (g1-g2) * i / steps;
\r
2498 BYTE b = b1 - (b1-b2) * i / steps;
\r
2500 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2501 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2502 FillRect( hdc, &rc, hbrush );
\r
2503 DeleteObject(hbrush);
\r
2506 else if( mode == 2 ) {
\r
2507 /* Diagonal gradient, good more or less for every piece */
\r
2508 POINT triangle[3];
\r
2509 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2510 HBRUSH hbrush_old;
\r
2511 int steps = squareSize;
\r
2514 triangle[0].x = squareSize - steps;
\r
2515 triangle[0].y = squareSize;
\r
2516 triangle[1].x = squareSize;
\r
2517 triangle[1].y = squareSize;
\r
2518 triangle[2].x = squareSize;
\r
2519 triangle[2].y = squareSize - steps;
\r
2521 for( i=0; i<steps; i++ ) {
\r
2522 BYTE r = r1 - (r1-r2) * i / steps;
\r
2523 BYTE g = g1 - (g1-g2) * i / steps;
\r
2524 BYTE b = b1 - (b1-b2) * i / steps;
\r
2526 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2527 hbrush_old = SelectObject( hdc, hbrush );
\r
2528 Polygon( hdc, triangle, 3 );
\r
2529 SelectObject( hdc, hbrush_old );
\r
2530 DeleteObject(hbrush);
\r
2535 SelectObject( hdc, hpen );
\r
2540 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2541 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2542 piece: follow the steps as explained below.
\r
2544 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2548 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2552 int backColor = whitePieceColor;
\r
2553 int foreColor = blackPieceColor;
\r
2555 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2556 backColor = appData.fontBackColorWhite;
\r
2557 foreColor = appData.fontForeColorWhite;
\r
2559 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2560 backColor = appData.fontBackColorBlack;
\r
2561 foreColor = appData.fontForeColorBlack;
\r
2565 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2567 hbm_old = SelectObject( hdc, hbm );
\r
2571 rc.right = squareSize;
\r
2572 rc.bottom = squareSize;
\r
2574 /* Step 1: background is now black */
\r
2575 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2577 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2579 pt.x = (squareSize - sz.cx) / 2;
\r
2580 pt.y = (squareSize - sz.cy) / 2;
\r
2582 SetBkMode( hdc, TRANSPARENT );
\r
2583 SetTextColor( hdc, chroma );
\r
2584 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2585 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2587 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2588 /* Step 3: the area outside the piece is filled with white */
\r
2589 // FloodFill( hdc, 0, 0, chroma );
\r
2590 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2591 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2592 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2593 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2594 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2596 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2597 but if the start point is not inside the piece we're lost!
\r
2598 There should be a better way to do this... if we could create a region or path
\r
2599 from the fill operation we would be fine for example.
\r
2601 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2602 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2604 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2605 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2606 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2608 SelectObject( dc2, bm2 );
\r
2609 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2610 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2611 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2612 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2613 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2616 DeleteObject( bm2 );
\r
2619 SetTextColor( hdc, 0 );
\r
2621 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2622 draw the piece again in black for safety.
\r
2624 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2626 SelectObject( hdc, hbm_old );
\r
2628 if( hPieceMask[index] != NULL ) {
\r
2629 DeleteObject( hPieceMask[index] );
\r
2632 hPieceMask[index] = hbm;
\r
2635 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2637 SelectObject( hdc, hbm );
\r
2640 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2641 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2642 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2644 SelectObject( dc1, hPieceMask[index] );
\r
2645 SelectObject( dc2, bm2 );
\r
2646 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2647 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2650 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2651 the piece background and deletes (makes transparent) the rest.
\r
2652 Thanks to that mask, we are free to paint the background with the greates
\r
2653 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2654 We use this, to make gradients and give the pieces a "roundish" look.
\r
2656 SetPieceBackground( hdc, backColor, 2 );
\r
2657 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2661 DeleteObject( bm2 );
\r
2664 SetTextColor( hdc, foreColor );
\r
2665 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2667 SelectObject( hdc, hbm_old );
\r
2669 if( hPieceFace[index] != NULL ) {
\r
2670 DeleteObject( hPieceFace[index] );
\r
2673 hPieceFace[index] = hbm;
\r
2676 static int TranslatePieceToFontPiece( int piece )
\r
2706 case BlackMarshall:
\r
2710 case BlackNightrider:
\r
2716 case BlackUnicorn:
\r
2720 case BlackGrasshopper:
\r
2732 case BlackCardinal:
\r
2739 case WhiteMarshall:
\r
2743 case WhiteNightrider:
\r
2749 case WhiteUnicorn:
\r
2753 case WhiteGrasshopper:
\r
2765 case WhiteCardinal:
\r
2774 void CreatePiecesFromFont()
\r
2777 HDC hdc_window = NULL;
\r
2783 if( fontBitmapSquareSize < 0 ) {
\r
2784 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2788 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2789 fontBitmapSquareSize = -1;
\r
2793 if( fontBitmapSquareSize != squareSize ) {
\r
2794 hdc_window = GetDC( hwndMain );
\r
2795 hdc = CreateCompatibleDC( hdc_window );
\r
2797 if( hPieceFont != NULL ) {
\r
2798 DeleteObject( hPieceFont );
\r
2801 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2802 hPieceMask[i] = NULL;
\r
2803 hPieceFace[i] = NULL;
\r
2809 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2810 fontHeight = appData.fontPieceSize;
\r
2813 fontHeight = (fontHeight * squareSize) / 100;
\r
2815 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2817 lf.lfEscapement = 0;
\r
2818 lf.lfOrientation = 0;
\r
2819 lf.lfWeight = FW_NORMAL;
\r
2821 lf.lfUnderline = 0;
\r
2822 lf.lfStrikeOut = 0;
\r
2823 lf.lfCharSet = DEFAULT_CHARSET;
\r
2824 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2825 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2826 lf.lfQuality = PROOF_QUALITY;
\r
2827 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2828 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2829 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2831 hPieceFont = CreateFontIndirect( &lf );
\r
2833 if( hPieceFont == NULL ) {
\r
2834 fontBitmapSquareSize = -2;
\r
2837 /* Setup font-to-piece character table */
\r
2838 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2839 /* No (or wrong) global settings, try to detect the font */
\r
2840 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2842 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2844 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2845 /* DiagramTT* family */
\r
2846 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2848 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2849 /* Fairy symbols */
\r
2850 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2852 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2853 /* Good Companion (Some characters get warped as literal :-( */
\r
2854 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2855 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2856 SetCharTable(pieceToFontChar, s);
\r
2859 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2860 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2864 /* Create bitmaps */
\r
2865 hfont_old = SelectObject( hdc, hPieceFont );
\r
2867 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2868 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2869 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2870 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2875 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2913 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2914 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2917 SelectObject( hdc, hfont_old );
\r
2919 fontBitmapSquareSize = squareSize;
\r
2923 if( hdc != NULL ) {
\r
2927 if( hdc_window != NULL ) {
\r
2928 ReleaseDC( hwndMain, hdc_window );
\r
2933 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2937 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2938 if (gameInfo.event &&
\r
2939 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2940 strcmp(name, "k80s") == 0) {
\r
2941 strcpy(name, "tim");
\r
2943 return LoadBitmap(hinst, name);
\r
2947 /* Insert a color into the program's logical palette
\r
2948 structure. This code assumes the given color is
\r
2949 the result of the RGB or PALETTERGB macro, and it
\r
2950 knows how those macros work (which is documented).
\r
2953 InsertInPalette(COLORREF color)
\r
2955 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2957 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2958 DisplayFatalError("Too many colors", 0, 1);
\r
2959 pLogPal->palNumEntries--;
\r
2963 pe->peFlags = (char) 0;
\r
2964 pe->peRed = (char) (0xFF & color);
\r
2965 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2966 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2972 InitDrawingColors()
\r
2974 if (pLogPal == NULL) {
\r
2975 /* Allocate enough memory for a logical palette with
\r
2976 * PALETTESIZE entries and set the size and version fields
\r
2977 * of the logical palette structure.
\r
2979 pLogPal = (NPLOGPALETTE)
\r
2980 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2981 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2982 pLogPal->palVersion = 0x300;
\r
2984 pLogPal->palNumEntries = 0;
\r
2986 InsertInPalette(lightSquareColor);
\r
2987 InsertInPalette(darkSquareColor);
\r
2988 InsertInPalette(whitePieceColor);
\r
2989 InsertInPalette(blackPieceColor);
\r
2990 InsertInPalette(highlightSquareColor);
\r
2991 InsertInPalette(premoveHighlightColor);
\r
2993 /* create a logical color palette according the information
\r
2994 * in the LOGPALETTE structure.
\r
2996 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2998 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2999 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3000 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3001 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3002 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3003 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3005 /* [AS] Force rendering of the font-based pieces */
\r
3006 if( fontBitmapSquareSize > 0 ) {
\r
3007 fontBitmapSquareSize = 0;
\r
3013 BoardWidth(int boardSize, int n)
\r
3014 { /* [HGM] argument n added to allow different width and height */
\r
3015 int lineGap = sizeInfo[boardSize].lineGap;
\r
3017 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3018 lineGap = appData.overrideLineGap;
\r
3021 return (n + 1) * lineGap +
\r
3022 n * sizeInfo[boardSize].squareSize;
\r
3025 /* Respond to board resize by dragging edge */
\r
3027 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3029 BoardSize newSize = NUM_SIZES - 1;
\r
3030 static int recurse = 0;
\r
3031 if (IsIconic(hwndMain)) return;
\r
3032 if (recurse > 0) return;
\r
3034 while (newSize > 0) {
\r
3035 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3036 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3037 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3040 boardSize = newSize;
\r
3041 InitDrawingSizes(boardSize, flags);
\r
3048 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3050 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3051 ChessSquare piece;
\r
3052 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3054 SIZE clockSize, messageSize;
\r
3056 char buf[MSG_SIZ];
\r
3058 HMENU hmenu = GetMenu(hwndMain);
\r
3059 RECT crect, wrect;
\r
3061 LOGBRUSH logbrush;
\r
3063 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3064 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3066 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3067 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3069 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3070 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3071 squareSize = sizeInfo[boardSize].squareSize;
\r
3072 lineGap = sizeInfo[boardSize].lineGap;
\r
3073 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3075 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3076 lineGap = appData.overrideLineGap;
\r
3079 if (tinyLayout != oldTinyLayout) {
\r
3080 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3082 style &= ~WS_SYSMENU;
\r
3083 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3084 "&Minimize\tCtrl+F4");
\r
3086 style |= WS_SYSMENU;
\r
3087 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3089 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3091 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3092 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3093 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3095 DrawMenuBar(hwndMain);
\r
3098 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3099 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3101 /* Get text area sizes */
\r
3102 hdc = GetDC(hwndMain);
\r
3103 if (appData.clockMode) {
\r
3104 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3106 sprintf(buf, "White");
\r
3108 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3109 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3110 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3111 str = "We only care about the height here";
\r
3112 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3113 SelectObject(hdc, oldFont);
\r
3114 ReleaseDC(hwndMain, hdc);
\r
3116 /* Compute where everything goes */
\r
3117 if(first.programLogo || second.programLogo) {
\r
3118 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3119 logoHeight = 2*clockSize.cy;
\r
3120 leftLogoRect.left = OUTER_MARGIN;
\r
3121 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3122 leftLogoRect.top = OUTER_MARGIN;
\r
3123 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3125 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3126 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3127 rightLogoRect.top = OUTER_MARGIN;
\r
3128 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3131 blackRect.left = leftLogoRect.right;
\r
3132 blackRect.right = rightLogoRect.left;
\r
3133 blackRect.top = OUTER_MARGIN;
\r
3134 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3136 whiteRect.left = blackRect.left ;
\r
3137 whiteRect.right = blackRect.right;
\r
3138 whiteRect.top = blackRect.bottom;
\r
3139 whiteRect.bottom = leftLogoRect.bottom;
\r
3141 whiteRect.left = OUTER_MARGIN;
\r
3142 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3143 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3144 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3146 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3147 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3148 blackRect.top = whiteRect.top;
\r
3149 blackRect.bottom = whiteRect.bottom;
\r
3152 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3153 if (appData.showButtonBar) {
\r
3154 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3155 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3157 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3159 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3160 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3162 boardRect.left = OUTER_MARGIN;
\r
3163 boardRect.right = boardRect.left + boardWidth;
\r
3164 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3165 boardRect.bottom = boardRect.top + boardHeight;
\r
3167 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3168 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3169 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3170 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3171 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3172 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3173 GetWindowRect(hwndMain, &wrect);
\r
3174 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3175 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3176 /* compensate if menu bar wrapped */
\r
3177 GetClientRect(hwndMain, &crect);
\r
3178 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3179 winHeight += offby;
\r
3181 case WMSZ_TOPLEFT:
\r
3182 SetWindowPos(hwndMain, NULL,
\r
3183 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3184 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3187 case WMSZ_TOPRIGHT:
\r
3189 SetWindowPos(hwndMain, NULL,
\r
3190 wrect.left, wrect.bottom - winHeight,
\r
3191 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3194 case WMSZ_BOTTOMLEFT:
\r
3196 SetWindowPos(hwndMain, NULL,
\r
3197 wrect.right - winWidth, wrect.top,
\r
3198 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3201 case WMSZ_BOTTOMRIGHT:
\r
3205 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3206 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3211 for (i = 0; i < N_BUTTONS; i++) {
\r
3212 if (buttonDesc[i].hwnd != NULL) {
\r
3213 DestroyWindow(buttonDesc[i].hwnd);
\r
3214 buttonDesc[i].hwnd = NULL;
\r
3216 if (appData.showButtonBar) {
\r
3217 buttonDesc[i].hwnd =
\r
3218 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3219 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3220 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3221 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3222 (HMENU) buttonDesc[i].id,
\r
3223 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3225 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3226 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3227 MAKELPARAM(FALSE, 0));
\r
3229 if (buttonDesc[i].id == IDM_Pause)
\r
3230 hwndPause = buttonDesc[i].hwnd;
\r
3231 buttonDesc[i].wndproc = (WNDPROC)
\r
3232 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3235 if (gridPen != NULL) DeleteObject(gridPen);
\r
3236 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3237 if (premovePen != NULL) DeleteObject(premovePen);
\r
3238 if (lineGap != 0) {
\r
3239 logbrush.lbStyle = BS_SOLID;
\r
3240 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3242 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3243 lineGap, &logbrush, 0, NULL);
\r
3244 logbrush.lbColor = highlightSquareColor;
\r
3246 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3247 lineGap, &logbrush, 0, NULL);
\r
3249 logbrush.lbColor = premoveHighlightColor;
\r
3251 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3252 lineGap, &logbrush, 0, NULL);
\r
3254 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3255 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3256 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3257 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3258 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3259 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3260 BOARD_WIDTH * (squareSize + lineGap);
\r
3261 lineGap / 2 + (i * (squareSize + lineGap));
\r
3262 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3264 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3265 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3266 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3267 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3268 lineGap / 2 + (i * (squareSize + lineGap));
\r
3269 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3270 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3271 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3275 /* [HGM] Licensing requirement */
\r
3277 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3280 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3282 GothicPopUp( "", VariantNormal);
\r
3285 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3286 oldBoardSize = boardSize;
\r
3287 oldTinyLayout = tinyLayout;
\r
3289 /* Load piece bitmaps for this board size */
\r
3290 for (i=0; i<=2; i++) {
\r
3291 for (piece = WhitePawn;
\r
3292 (int) piece < (int) BlackPawn;
\r
3293 piece = (ChessSquare) ((int) piece + 1)) {
\r
3294 if (pieceBitmap[i][piece] != NULL)
\r
3295 DeleteObject(pieceBitmap[i][piece]);
\r
3299 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3300 // Orthodox Chess pieces
\r
3301 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3302 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3303 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3304 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3305 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3306 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3307 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3308 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3309 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3310 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3311 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3312 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3313 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3314 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3315 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3316 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3317 // in Shogi, Hijack the unused Queen for Lance
\r
3318 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3319 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3320 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3322 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3323 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3324 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3327 if(squareSize <= 72 && squareSize >= 33) {
\r
3328 /* A & C are available in most sizes now */
\r
3329 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3330 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3331 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3332 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3333 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3334 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3335 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3336 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3337 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3338 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3339 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3342 } else { // Smirf-like
\r
3343 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3344 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3345 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3347 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3348 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3349 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3350 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3351 } else { // WinBoard standard
\r
3352 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3353 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3354 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3359 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3360 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3361 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3362 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3363 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3366 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3367 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3368 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3369 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3370 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3371 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3372 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3373 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3374 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3375 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3376 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3377 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3378 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3379 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3380 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3381 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3382 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3383 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3384 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3385 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3386 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3387 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3388 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3389 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3391 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3392 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3393 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3394 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3398 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3399 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3400 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3405 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3411 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3412 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3413 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3414 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3415 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3416 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3419 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3420 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3421 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3422 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3423 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3424 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3425 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3426 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3427 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3428 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3429 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3430 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3431 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3432 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3433 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3437 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3438 /* special Shogi support in this size */
\r
3439 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3440 for (piece = WhitePawn;
\r
3441 (int) piece < (int) BlackPawn;
\r
3442 piece = (ChessSquare) ((int) piece + 1)) {
\r
3443 if (pieceBitmap[i][piece] != NULL)
\r
3444 DeleteObject(pieceBitmap[i][piece]);
\r
3447 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3448 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3449 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3450 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3451 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3452 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3453 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3454 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3455 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3456 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3457 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3458 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3459 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3460 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3461 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3462 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3463 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3464 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3465 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3466 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3467 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3468 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3469 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3470 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3471 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3472 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3473 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3475 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3476 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3477 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3478 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3479 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3486 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3487 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3488 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3494 PieceBitmap(ChessSquare p, int kind)
\r
3496 if ((int) p >= (int) BlackPawn)
\r
3497 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3499 return pieceBitmap[kind][(int) p];
\r
3502 /***************************************************************/
\r
3504 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3505 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3507 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3508 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3512 SquareToPos(int row, int column, int * x, int * y)
\r
3515 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3516 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3518 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3519 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3524 DrawCoordsOnDC(HDC hdc)
\r
3526 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
3527 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
3528 char str[2] = { NULLCHAR, NULLCHAR };
\r
3529 int oldMode, oldAlign, x, y, start, i;
\r
3533 if (!appData.showCoords)
\r
3536 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3538 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3539 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3540 oldAlign = GetTextAlign(hdc);
\r
3541 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3543 y = boardRect.top + lineGap;
\r
3544 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3546 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3547 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3548 str[0] = files[start + i];
\r
3549 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3550 y += squareSize + lineGap;
\r
3553 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3555 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3556 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3557 str[0] = ranks[start + i];
\r
3558 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3559 x += squareSize + lineGap;
\r
3562 SelectObject(hdc, oldBrush);
\r
3563 SetBkMode(hdc, oldMode);
\r
3564 SetTextAlign(hdc, oldAlign);
\r
3565 SelectObject(hdc, oldFont);
\r
3569 DrawGridOnDC(HDC hdc)
\r
3573 if (lineGap != 0) {
\r
3574 oldPen = SelectObject(hdc, gridPen);
\r
3575 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3576 SelectObject(hdc, oldPen);
\r
3580 #define HIGHLIGHT_PEN 0
\r
3581 #define PREMOVE_PEN 1
\r
3584 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3587 HPEN oldPen, hPen;
\r
3588 if (lineGap == 0) return;
\r
3590 x1 = boardRect.left +
\r
3591 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3592 y1 = boardRect.top +
\r
3593 lineGap/2 + y * (squareSize + lineGap);
\r
3595 x1 = boardRect.left +
\r
3596 lineGap/2 + x * (squareSize + lineGap);
\r
3597 y1 = boardRect.top +
\r
3598 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3600 hPen = pen ? premovePen : highlightPen;
\r
3601 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3602 MoveToEx(hdc, x1, y1, NULL);
\r
3603 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3604 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3605 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3606 LineTo(hdc, x1, y1);
\r
3607 SelectObject(hdc, oldPen);
\r
3611 DrawHighlightsOnDC(HDC hdc)
\r
3614 for (i=0; i<2; i++) {
\r
3615 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3616 DrawHighlightOnDC(hdc, TRUE,
\r
3617 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3620 for (i=0; i<2; i++) {
\r
3621 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3622 premoveHighlightInfo.sq[i].y >= 0) {
\r
3623 DrawHighlightOnDC(hdc, TRUE,
\r
3624 premoveHighlightInfo.sq[i].x,
\r
3625 premoveHighlightInfo.sq[i].y,
\r
3631 /* Note: sqcolor is used only in monoMode */
\r
3632 /* Note that this code is largely duplicated in woptions.c,
\r
3633 function DrawSampleSquare, so that needs to be updated too */
\r
3635 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3637 HBITMAP oldBitmap;
\r
3641 if (appData.blindfold) return;
\r
3643 /* [AS] Use font-based pieces if needed */
\r
3644 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3645 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3646 CreatePiecesFromFont();
\r
3648 if( fontBitmapSquareSize == squareSize ) {
\r
3649 int index = TranslatePieceToFontPiece(piece);
\r
3651 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3655 squareSize, squareSize,
\r
3660 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3664 squareSize, squareSize,
\r
3673 if (appData.monoMode) {
\r
3674 SelectObject(tmphdc, PieceBitmap(piece,
\r
3675 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3676 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3677 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3679 tmpSize = squareSize;
\r
3681 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3682 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3683 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3684 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3685 x += (squareSize - minorSize)>>1;
\r
3686 y += squareSize - minorSize - 2;
\r
3687 tmpSize = minorSize;
\r
3689 if (color || appData.allWhite ) {
\r
3690 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3692 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3693 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3694 if(appData.upsideDown && color==flipView)
\r
3695 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3697 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3699 /* Use black piece color for outline of white pieces */
\r
3700 /* Not sure this looks really good (though xboard does it).
\r
3701 Maybe better to have another selectable color, default black */
\r
3702 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3703 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3704 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3706 /* Use black for outline of white pieces */
\r
3707 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3708 if(appData.upsideDown && color==flipView)
\r
3709 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3711 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3715 /* Use white piece color for details of black pieces */
\r
3716 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3717 WHITE_PIECE ones aren't always the right shape. */
\r
3718 /* Not sure this looks really good (though xboard does it).
\r
3719 Maybe better to have another selectable color, default medium gray? */
\r
3720 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3721 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3722 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3723 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3724 SelectObject(hdc, blackPieceBrush);
\r
3725 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3727 /* Use square color for details of black pieces */
\r
3728 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3729 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3730 if(appData.upsideDown && !flipView)
\r
3731 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3733 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3736 SelectObject(hdc, oldBrush);
\r
3737 SelectObject(tmphdc, oldBitmap);
\r
3741 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3742 int GetBackTextureMode( int algo )
\r
3744 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3748 case BACK_TEXTURE_MODE_PLAIN:
\r
3749 result = 1; /* Always use identity map */
\r
3751 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3752 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3760 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3761 to handle redraws cleanly (as random numbers would always be different).
\r
3763 VOID RebuildTextureSquareInfo()
\r
3773 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3775 if( liteBackTexture != NULL ) {
\r
3776 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3777 lite_w = bi.bmWidth;
\r
3778 lite_h = bi.bmHeight;
\r
3782 if( darkBackTexture != NULL ) {
\r
3783 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3784 dark_w = bi.bmWidth;
\r
3785 dark_h = bi.bmHeight;
\r
3789 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3790 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3791 if( (col + row) & 1 ) {
\r
3793 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3794 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3795 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3796 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3801 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3802 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3803 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3804 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3811 /* [AS] Arrow highlighting support */
\r
3813 static int A_WIDTH = 5; /* Width of arrow body */
\r
3815 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3816 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3818 static double Sqr( double x )
\r
3823 static int Round( double x )
\r
3825 return (int) (x + 0.5);
\r
3828 /* Draw an arrow between two points using current settings */
\r
3829 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3832 double dx, dy, j, k, x, y;
\r
3834 if( d_x == s_x ) {
\r
3835 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3837 arrow[0].x = s_x + A_WIDTH;
\r
3840 arrow[1].x = s_x + A_WIDTH;
\r
3841 arrow[1].y = d_y - h;
\r
3843 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3844 arrow[2].y = d_y - h;
\r
3849 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3850 arrow[4].y = d_y - h;
\r
3852 arrow[5].x = s_x - A_WIDTH;
\r
3853 arrow[5].y = d_y - h;
\r
3855 arrow[6].x = s_x - A_WIDTH;
\r
3858 else if( d_y == s_y ) {
\r
3859 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3862 arrow[0].y = s_y + A_WIDTH;
\r
3864 arrow[1].x = d_x - w;
\r
3865 arrow[1].y = s_y + A_WIDTH;
\r
3867 arrow[2].x = d_x - w;
\r
3868 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3873 arrow[4].x = d_x - w;
\r
3874 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3876 arrow[5].x = d_x - w;
\r
3877 arrow[5].y = s_y - A_WIDTH;
\r
3880 arrow[6].y = s_y - A_WIDTH;
\r
3883 /* [AS] Needed a lot of paper for this! :-) */
\r
3884 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3885 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3887 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3889 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3894 arrow[0].x = Round(x - j);
\r
3895 arrow[0].y = Round(y + j*dx);
\r
3897 arrow[1].x = Round(x + j);
\r
3898 arrow[1].y = Round(y - j*dx);
\r
3901 x = (double) d_x - k;
\r
3902 y = (double) d_y - k*dy;
\r
3905 x = (double) d_x + k;
\r
3906 y = (double) d_y + k*dy;
\r
3909 arrow[2].x = Round(x + j);
\r
3910 arrow[2].y = Round(y - j*dx);
\r
3912 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3913 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3918 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3919 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3921 arrow[6].x = Round(x - j);
\r
3922 arrow[6].y = Round(y + j*dx);
\r
3925 Polygon( hdc, arrow, 7 );
\r
3928 /* [AS] Draw an arrow between two squares */
\r
3929 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3931 int s_x, s_y, d_x, d_y;
\r
3938 if( s_col == d_col && s_row == d_row ) {
\r
3942 /* Get source and destination points */
\r
3943 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3944 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3947 d_y += squareSize / 4;
\r
3949 else if( d_y < s_y ) {
\r
3950 d_y += 3 * squareSize / 4;
\r
3953 d_y += squareSize / 2;
\r
3957 d_x += squareSize / 4;
\r
3959 else if( d_x < s_x ) {
\r
3960 d_x += 3 * squareSize / 4;
\r
3963 d_x += squareSize / 2;
\r
3966 s_x += squareSize / 2;
\r
3967 s_y += squareSize / 2;
\r
3969 /* Adjust width */
\r
3970 A_WIDTH = squareSize / 14;
\r
3973 stLB.lbStyle = BS_SOLID;
\r
3974 stLB.lbColor = appData.highlightArrowColor;
\r
3977 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3978 holdpen = SelectObject( hdc, hpen );
\r
3979 hbrush = CreateBrushIndirect( &stLB );
\r
3980 holdbrush = SelectObject( hdc, hbrush );
\r
3982 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3984 SelectObject( hdc, holdpen );
\r
3985 SelectObject( hdc, holdbrush );
\r
3986 DeleteObject( hpen );
\r
3987 DeleteObject( hbrush );
\r
3990 BOOL HasHighlightInfo()
\r
3992 BOOL result = FALSE;
\r
3994 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3995 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4003 BOOL IsDrawArrowEnabled()
\r
4005 BOOL result = FALSE;
\r
4007 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4014 VOID DrawArrowHighlight( HDC hdc )
\r
4016 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4017 DrawArrowBetweenSquares( hdc,
\r
4018 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4019 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4023 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4025 HRGN result = NULL;
\r
4027 if( HasHighlightInfo() ) {
\r
4028 int x1, y1, x2, y2;
\r
4029 int sx, sy, dx, dy;
\r
4031 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4032 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4034 sx = MIN( x1, x2 );
\r
4035 sy = MIN( y1, y2 );
\r
4036 dx = MAX( x1, x2 ) + squareSize;
\r
4037 dy = MAX( y1, y2 ) + squareSize;
\r
4039 result = CreateRectRgn( sx, sy, dx, dy );
\r
4046 Warning: this function modifies the behavior of several other functions.
\r
4048 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4049 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4050 repaint is scattered all over the place, which is not good for features such as
\r
4051 "arrow highlighting" that require a full repaint of the board.
\r
4053 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4054 user interaction, when speed is not so important) but especially to avoid errors
\r
4055 in the displayed graphics.
\r
4057 In such patched places, I always try refer to this function so there is a single
\r
4058 place to maintain knowledge.
\r
4060 To restore the original behavior, just return FALSE unconditionally.
\r
4062 BOOL IsFullRepaintPreferrable()
\r
4064 BOOL result = FALSE;
\r
4066 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4067 /* Arrow may appear on the board */
\r
4075 This function is called by DrawPosition to know whether a full repaint must
\r
4078 Only DrawPosition may directly call this function, which makes use of
\r
4079 some state information. Other function should call DrawPosition specifying
\r
4080 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4082 BOOL DrawPositionNeedsFullRepaint()
\r
4084 BOOL result = FALSE;
\r
4087 Probably a slightly better policy would be to trigger a full repaint
\r
4088 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4089 but animation is fast enough that it's difficult to notice.
\r
4091 if( animInfo.piece == EmptySquare ) {
\r
4092 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4101 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4103 int row, column, x, y, square_color, piece_color;
\r
4104 ChessSquare piece;
\r
4106 HDC texture_hdc = NULL;
\r
4108 /* [AS] Initialize background textures if needed */
\r
4109 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4110 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4111 if( backTextureSquareSize != squareSize
\r
4112 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4113 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4114 backTextureSquareSize = squareSize;
\r
4115 RebuildTextureSquareInfo();
\r
4118 texture_hdc = CreateCompatibleDC( hdc );
\r
4121 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4122 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4124 SquareToPos(row, column, &x, &y);
\r
4126 piece = board[row][column];
\r
4128 square_color = ((column + row) % 2) == 1;
\r
4129 if( gameInfo.variant == VariantXiangqi ) {
\r
4130 square_color = !InPalace(row, column);
\r
4131 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4132 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4134 piece_color = (int) piece < (int) BlackPawn;
\r
4137 /* [HGM] holdings file: light square or black */
\r
4138 if(column == BOARD_LEFT-2) {
\r
4139 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4142 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4146 if(column == BOARD_RGHT + 1 ) {
\r
4147 if( row < gameInfo.holdingsSize )
\r
4150 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4154 if(column == BOARD_LEFT-1 ) /* left align */
\r
4155 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4156 else if( column == BOARD_RGHT) /* right align */
\r
4157 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4159 if (appData.monoMode) {
\r
4160 if (piece == EmptySquare) {
\r
4161 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4162 square_color ? WHITENESS : BLACKNESS);
\r
4164 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4167 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4168 /* [AS] Draw the square using a texture bitmap */
\r
4169 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4170 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4171 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4174 squareSize, squareSize,
\r
4177 backTextureSquareInfo[r][c].mode,
\r
4178 backTextureSquareInfo[r][c].x,
\r
4179 backTextureSquareInfo[r][c].y );
\r
4181 SelectObject( texture_hdc, hbm );
\r
4183 if (piece != EmptySquare) {
\r
4184 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4188 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4190 oldBrush = SelectObject(hdc, brush );
\r
4191 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4192 SelectObject(hdc, oldBrush);
\r
4193 if (piece != EmptySquare)
\r
4194 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4199 if( texture_hdc != NULL ) {
\r
4200 DeleteDC( texture_hdc );
\r
4204 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4205 void fputDW(FILE *f, int x)
\r
4207 fputc(x & 255, f);
\r
4208 fputc(x>>8 & 255, f);
\r
4209 fputc(x>>16 & 255, f);
\r
4210 fputc(x>>24 & 255, f);
\r
4213 #define MAX_CLIPS 200 /* more than enough */
\r
4216 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4218 HBITMAP bufferBitmap;
\r
4223 int w = 100, h = 50;
\r
4225 if(cps->programLogo == NULL) return;
\r
4226 // GetClientRect(hwndMain, &Rect);
\r
4227 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4228 // Rect.bottom-Rect.top+1);
\r
4229 tmphdc = CreateCompatibleDC(hdc);
\r
4230 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4231 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4235 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4236 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4237 SelectObject(tmphdc, hbm);
\r
4242 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4244 static Board lastReq, lastDrawn;
\r
4245 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4246 static int lastDrawnFlipView = 0;
\r
4247 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4248 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4251 HBITMAP bufferBitmap;
\r
4252 HBITMAP oldBitmap;
\r
4254 HRGN clips[MAX_CLIPS];
\r
4255 ChessSquare dragged_piece = EmptySquare;
\r
4257 /* I'm undecided on this - this function figures out whether a full
\r
4258 * repaint is necessary on its own, so there's no real reason to have the
\r
4259 * caller tell it that. I think this can safely be set to FALSE - but
\r
4260 * if we trust the callers not to request full repaints unnessesarily, then
\r
4261 * we could skip some clipping work. In other words, only request a full
\r
4262 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4263 * gamestart and similar) --Hawk
\r
4265 Boolean fullrepaint = repaint;
\r
4267 if( DrawPositionNeedsFullRepaint() ) {
\r
4268 fullrepaint = TRUE;
\r
4272 if( fullrepaint ) {
\r
4273 static int repaint_count = 0;
\r
4277 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4278 OutputDebugString( buf );
\r
4282 if (board == NULL) {
\r
4283 if (!lastReqValid) {
\r
4288 CopyBoard(lastReq, board);
\r
4292 if (doingSizing) {
\r
4296 if (IsIconic(hwndMain)) {
\r
4300 if (hdc == NULL) {
\r
4301 hdc = GetDC(hwndMain);
\r
4302 if (!appData.monoMode) {
\r
4303 SelectPalette(hdc, hPal, FALSE);
\r
4304 RealizePalette(hdc);
\r
4308 releaseDC = FALSE;
\r
4312 fprintf(debugFP, "*******************************\n"
\r
4314 "dragInfo.from (%d,%d)\n"
\r
4315 "dragInfo.start (%d,%d)\n"
\r
4316 "dragInfo.pos (%d,%d)\n"
\r
4317 "dragInfo.lastpos (%d,%d)\n",
\r
4318 repaint ? "TRUE" : "FALSE",
\r
4319 dragInfo.from.x, dragInfo.from.y,
\r
4320 dragInfo.start.x, dragInfo.start.y,
\r
4321 dragInfo.pos.x, dragInfo.pos.y,
\r
4322 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4323 fprintf(debugFP, "prev: ");
\r
4324 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4325 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4326 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4329 fprintf(debugFP, "\n");
\r
4330 fprintf(debugFP, "board: ");
\r
4331 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4332 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4333 fprintf(debugFP, "%d ", board[row][column]);
\r
4336 fprintf(debugFP, "\n");
\r
4340 /* Create some work-DCs */
\r
4341 hdcmem = CreateCompatibleDC(hdc);
\r
4342 tmphdc = CreateCompatibleDC(hdc);
\r
4344 /* If dragging is in progress, we temporarely remove the piece */
\r
4345 /* [HGM] or temporarily decrease count if stacked */
\r
4346 /* !! Moved to before board compare !! */
\r
4347 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4348 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4349 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4350 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4351 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4353 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4354 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4355 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4357 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4360 /* Figure out which squares need updating by comparing the
\r
4361 * newest board with the last drawn board and checking if
\r
4362 * flipping has changed.
\r
4364 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4365 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4366 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4367 if (lastDrawn[row][column] != board[row][column]) {
\r
4368 SquareToPos(row, column, &x, &y);
\r
4369 clips[num_clips++] =
\r
4370 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4374 for (i=0; i<2; i++) {
\r
4375 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4376 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4377 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4378 lastDrawnHighlight.sq[i].y >= 0) {
\r
4379 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4380 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4381 clips[num_clips++] =
\r
4382 CreateRectRgn(x - lineGap, y - lineGap,
\r
4383 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4385 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4386 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4387 clips[num_clips++] =
\r
4388 CreateRectRgn(x - lineGap, y - lineGap,
\r
4389 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4393 for (i=0; i<2; i++) {
\r
4394 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4395 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4396 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4397 lastDrawnPremove.sq[i].y >= 0) {
\r
4398 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4399 lastDrawnPremove.sq[i].x, &x, &y);
\r
4400 clips[num_clips++] =
\r
4401 CreateRectRgn(x - lineGap, y - lineGap,
\r
4402 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4404 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4405 premoveHighlightInfo.sq[i].y >= 0) {
\r
4406 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4407 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4408 clips[num_clips++] =
\r
4409 CreateRectRgn(x - lineGap, y - lineGap,
\r
4410 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4415 fullrepaint = TRUE;
\r
4418 /* Create a buffer bitmap - this is the actual bitmap
\r
4419 * being written to. When all the work is done, we can
\r
4420 * copy it to the real DC (the screen). This avoids
\r
4421 * the problems with flickering.
\r
4423 GetClientRect(hwndMain, &Rect);
\r
4424 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4425 Rect.bottom-Rect.top+1);
\r
4426 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4427 if (!appData.monoMode) {
\r
4428 SelectPalette(hdcmem, hPal, FALSE);
\r
4431 /* Create clips for dragging */
\r
4432 if (!fullrepaint) {
\r
4433 if (dragInfo.from.x >= 0) {
\r
4434 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4435 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4437 if (dragInfo.start.x >= 0) {
\r
4438 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4439 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4441 if (dragInfo.pos.x >= 0) {
\r
4442 x = dragInfo.pos.x - squareSize / 2;
\r
4443 y = dragInfo.pos.y - squareSize / 2;
\r
4444 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4446 if (dragInfo.lastpos.x >= 0) {
\r
4447 x = dragInfo.lastpos.x - squareSize / 2;
\r
4448 y = dragInfo.lastpos.y - squareSize / 2;
\r
4449 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4453 /* Are we animating a move?
\r
4455 * - remove the piece from the board (temporarely)
\r
4456 * - calculate the clipping region
\r
4458 if (!fullrepaint) {
\r
4459 if (animInfo.piece != EmptySquare) {
\r
4460 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4461 x = boardRect.left + animInfo.lastpos.x;
\r
4462 y = boardRect.top + animInfo.lastpos.y;
\r
4463 x2 = boardRect.left + animInfo.pos.x;
\r
4464 y2 = boardRect.top + animInfo.pos.y;
\r
4465 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4466 /* Slight kludge. The real problem is that after AnimateMove is
\r
4467 done, the position on the screen does not match lastDrawn.
\r
4468 This currently causes trouble only on e.p. captures in
\r
4469 atomic, where the piece moves to an empty square and then
\r
4470 explodes. The old and new positions both had an empty square
\r
4471 at the destination, but animation has drawn a piece there and
\r
4472 we have to remember to erase it. */
\r
4473 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4477 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4478 if (num_clips == 0)
\r
4479 fullrepaint = TRUE;
\r
4481 /* Set clipping on the memory DC */
\r
4482 if (!fullrepaint) {
\r
4483 SelectClipRgn(hdcmem, clips[0]);
\r
4484 for (x = 1; x < num_clips; x++) {
\r
4485 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4486 abort(); // this should never ever happen!
\r
4490 /* Do all the drawing to the memory DC */
\r
4491 DrawGridOnDC(hdcmem);
\r
4492 DrawHighlightsOnDC(hdcmem);
\r
4493 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4496 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4497 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4500 if( appData.highlightMoveWithArrow ) {
\r
4501 DrawArrowHighlight(hdcmem);
\r
4504 DrawCoordsOnDC(hdcmem);
\r
4506 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4507 /* to make sure lastDrawn contains what is actually drawn */
\r
4509 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4510 if (dragged_piece != EmptySquare) {
\r
4511 /* [HGM] or restack */
\r
4512 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4513 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4515 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4516 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4517 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4518 x = dragInfo.pos.x - squareSize / 2;
\r
4519 y = dragInfo.pos.y - squareSize / 2;
\r
4520 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4521 ((int) dragged_piece < (int) BlackPawn),
\r
4522 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4525 /* Put the animated piece back into place and draw it */
\r
4526 if (animInfo.piece != EmptySquare) {
\r
4527 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4528 x = boardRect.left + animInfo.pos.x;
\r
4529 y = boardRect.top + animInfo.pos.y;
\r
4530 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4531 ((int) animInfo.piece < (int) BlackPawn),
\r
4532 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4535 /* Release the bufferBitmap by selecting in the old bitmap
\r
4536 * and delete the memory DC
\r
4538 SelectObject(hdcmem, oldBitmap);
\r
4541 /* Set clipping on the target DC */
\r
4542 if (!fullrepaint) {
\r
4543 SelectClipRgn(hdc, clips[0]);
\r
4544 for (x = 1; x < num_clips; x++) {
\r
4545 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4546 abort(); // this should never ever happen!
\r
4550 /* Copy the new bitmap onto the screen in one go.
\r
4551 * This way we avoid any flickering
\r
4553 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4554 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4555 boardRect.right - boardRect.left,
\r
4556 boardRect.bottom - boardRect.top,
\r
4557 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4558 if(saveDiagFlag) {
\r
4559 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4560 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4562 GetObject(bufferBitmap, sizeof(b), &b);
\r
4563 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4564 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4565 bih.biWidth = b.bmWidth;
\r
4566 bih.biHeight = b.bmHeight;
\r
4568 bih.biBitCount = b.bmBitsPixel;
\r
4569 bih.biCompression = 0;
\r
4570 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4571 bih.biXPelsPerMeter = 0;
\r
4572 bih.biYPelsPerMeter = 0;
\r
4573 bih.biClrUsed = 0;
\r
4574 bih.biClrImportant = 0;
\r
4575 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4576 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4577 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4578 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4581 wb = b.bmWidthBytes;
\r
4583 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4584 int k = ((int*) pData)[i];
\r
4585 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4586 if(j >= 16) break;
\r
4588 if(j >= nrColors) nrColors = j+1;
\r
4590 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4592 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4593 for(w=0; w<(wb>>2); w+=2) {
\r
4594 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4595 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4596 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4597 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4598 pData[p++] = m | j<<4;
\r
4600 while(p&3) pData[p++] = 0;
\r
4603 wb = (wb+31>>5)<<2;
\r
4605 // write BITMAPFILEHEADER
\r
4606 fprintf(diagFile, "BM");
\r
4607 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4608 fputDW(diagFile, 0);
\r
4609 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4610 // write BITMAPINFOHEADER
\r
4611 fputDW(diagFile, 40);
\r
4612 fputDW(diagFile, b.bmWidth);
\r
4613 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4614 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4615 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4616 fputDW(diagFile, 0);
\r
4617 fputDW(diagFile, 0);
\r
4618 fputDW(diagFile, 0);
\r
4619 fputDW(diagFile, 0);
\r
4620 fputDW(diagFile, 0);
\r
4621 fputDW(diagFile, 0);
\r
4622 // write color table
\r
4624 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4625 // write bitmap data
\r
4626 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4627 fputc(pData[i], diagFile);
\r
4632 SelectObject(tmphdc, oldBitmap);
\r
4634 /* Massive cleanup */
\r
4635 for (x = 0; x < num_clips; x++)
\r
4636 DeleteObject(clips[x]);
\r
4639 DeleteObject(bufferBitmap);
\r
4642 ReleaseDC(hwndMain, hdc);
\r
4644 if (lastDrawnFlipView != flipView) {
\r
4646 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4648 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4651 /* CopyBoard(lastDrawn, board);*/
\r
4652 lastDrawnHighlight = highlightInfo;
\r
4653 lastDrawnPremove = premoveHighlightInfo;
\r
4654 lastDrawnFlipView = flipView;
\r
4655 lastDrawnValid = 1;
\r
4658 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4666 saveDiagFlag = 1; diagFile = f;
\r
4667 HDCDrawPosition(NULL, TRUE, NULL);
\r
4671 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4678 /*---------------------------------------------------------------------------*\
\r
4679 | CLIENT PAINT PROCEDURE
\r
4680 | This is the main event-handler for the WM_PAINT message.
\r
4682 \*---------------------------------------------------------------------------*/
\r
4684 PaintProc(HWND hwnd)
\r
4690 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4691 if (IsIconic(hwnd)) {
\r
4692 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4694 if (!appData.monoMode) {
\r
4695 SelectPalette(hdc, hPal, FALSE);
\r
4696 RealizePalette(hdc);
\r
4698 HDCDrawPosition(hdc, 1, NULL);
\r
4700 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4701 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4702 ETO_CLIPPED|ETO_OPAQUE,
\r
4703 &messageRect, messageText, strlen(messageText), NULL);
\r
4704 SelectObject(hdc, oldFont);
\r
4705 DisplayBothClocks();
\r
4707 EndPaint(hwnd,&ps);
\r
4715 * If the user selects on a border boundary, return -1; if off the board,
\r
4716 * return -2. Otherwise map the event coordinate to the square.
\r
4717 * The offset boardRect.left or boardRect.top must already have been
\r
4718 * subtracted from x.
\r
4721 EventToSquare(int x)
\r
4728 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4730 x /= (squareSize + lineGap);
\r
4731 if (x >= BOARD_SIZE)
\r
4742 DropEnable dropEnables[] = {
\r
4743 { 'P', DP_Pawn, "Pawn" },
\r
4744 { 'N', DP_Knight, "Knight" },
\r
4745 { 'B', DP_Bishop, "Bishop" },
\r
4746 { 'R', DP_Rook, "Rook" },
\r
4747 { 'Q', DP_Queen, "Queen" },
\r
4751 SetupDropMenu(HMENU hmenu)
\r
4753 int i, count, enable;
\r
4755 extern char white_holding[], black_holding[];
\r
4756 char item[MSG_SIZ];
\r
4758 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4759 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4760 dropEnables[i].piece);
\r
4762 while (p && *p++ == dropEnables[i].piece) count++;
\r
4763 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4764 enable = count > 0 || !appData.testLegality
\r
4765 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4766 && !appData.icsActive);
\r
4767 ModifyMenu(hmenu, dropEnables[i].command,
\r
4768 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4769 dropEnables[i].command, item);
\r
4773 static int fromX = -1, fromY = -1, toX, toY;
\r
4775 /* Event handler for mouse messages */
\r
4777 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4781 static int recursive = 0;
\r
4783 BOOLEAN needsRedraw = FALSE;
\r
4784 BOOLEAN saveAnimate;
\r
4785 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4786 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4787 ChessMove moveType;
\r
4790 if (message == WM_MBUTTONUP) {
\r
4791 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4792 to the middle button: we simulate pressing the left button too!
\r
4794 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4795 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4801 pt.x = LOWORD(lParam);
\r
4802 pt.y = HIWORD(lParam);
\r
4803 x = EventToSquare(pt.x - boardRect.left);
\r
4804 y = EventToSquare(pt.y - boardRect.top);
\r
4805 if (!flipView && y >= 0) {
\r
4806 y = BOARD_HEIGHT - 1 - y;
\r
4808 if (flipView && x >= 0) {
\r
4809 x = BOARD_WIDTH - 1 - x;
\r
4812 switch (message) {
\r
4813 case WM_LBUTTONDOWN:
\r
4814 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4815 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4816 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4817 if(gameInfo.holdingsWidth &&
\r
4818 (WhiteOnMove(currentMove)
\r
4819 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4820 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4821 // click in right holdings, for determining promotion piece
\r
4822 ChessSquare p = boards[currentMove][y][x];
\r
4823 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4824 if(p != EmptySquare) {
\r
4825 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4826 fromX = fromY = -1;
\r
4830 DrawPosition(FALSE, boards[currentMove]);
\r
4834 sameAgain = FALSE;
\r
4836 /* Downclick vertically off board; check if on clock */
\r
4837 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4838 if (gameMode == EditPosition) {
\r
4839 SetWhiteToPlayEvent();
\r
4840 } else if (gameMode == IcsPlayingBlack ||
\r
4841 gameMode == MachinePlaysWhite) {
\r
4843 } else if (gameMode == EditGame) {
\r
4844 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4846 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4847 if (gameMode == EditPosition) {
\r
4848 SetBlackToPlayEvent();
\r
4849 } else if (gameMode == IcsPlayingWhite ||
\r
4850 gameMode == MachinePlaysBlack) {
\r
4852 } else if (gameMode == EditGame) {
\r
4853 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4856 if (!appData.highlightLastMove) {
\r
4857 ClearHighlights();
\r
4858 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4860 fromX = fromY = -1;
\r
4861 dragInfo.start.x = dragInfo.start.y = -1;
\r
4862 dragInfo.from = dragInfo.start;
\r
4864 } else if (x < 0 || y < 0
\r
4865 /* [HGM] block clicks between board and holdings */
\r
4866 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4867 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4868 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4869 /* EditPosition, empty square, or different color piece;
\r
4870 click-click move is possible */
\r
4873 } else if (fromX == x && fromY == y) {
\r
4874 /* Downclick on same square again */
\r
4875 ClearHighlights();
\r
4876 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4877 sameAgain = TRUE;
\r
4878 } else if (fromX != -1 &&
\r
4879 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4881 /* Downclick on different square. */
\r
4882 /* [HGM] if on holdings file, should count as new first click ! */
\r
4883 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4886 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4887 to make sure move is legal before showing promotion popup */
\r
4888 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4889 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4890 fromX = fromY = -1;
\r
4891 ClearHighlights();
\r
4892 DrawPosition(FALSE, boards[currentMove]);
\r
4895 if(moveType != ImpossibleMove) {
\r
4896 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4897 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4898 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4899 appData.alwaysPromoteToQueen) {
\r
4900 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4901 if (!appData.highlightLastMove) {
\r
4902 ClearHighlights();
\r
4903 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4906 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4907 SetHighlights(fromX, fromY, toX, toY);
\r
4908 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4909 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4910 If promotion to Q is legal, all are legal! */
\r
4911 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4912 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4913 // kludge to temporarily execute move on display, wthout promotng yet
\r
4914 promotionChoice = TRUE;
\r
4915 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4916 boards[currentMove][toY][toX] = p;
\r
4917 DrawPosition(FALSE, boards[currentMove]);
\r
4918 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4919 boards[currentMove][toY][toX] = q;
\r
4921 PromotionPopup(hwnd);
\r
4922 } else { /* not a promotion */
\r
4923 if (appData.animate || appData.highlightLastMove) {
\r
4924 SetHighlights(fromX, fromY, toX, toY);
\r
4926 ClearHighlights();
\r
4928 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4929 fromX = fromY = -1;
\r
4930 if (appData.animate && !appData.highlightLastMove) {
\r
4931 ClearHighlights();
\r
4932 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4938 /* [HGM] it seemed that braces were missing here */
\r
4939 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4940 fromX = fromY = -1;
\r
4944 ClearHighlights();
\r
4945 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4947 /* First downclick, or restart on a square with same color piece */
\r
4948 if (!frozen && OKToStartUserMove(x, y)) {
\r
4951 dragInfo.lastpos = pt;
\r
4952 dragInfo.from.x = fromX;
\r
4953 dragInfo.from.y = fromY;
\r
4954 dragInfo.start = dragInfo.from;
\r
4955 SetCapture(hwndMain);
\r
4957 fromX = fromY = -1;
\r
4958 dragInfo.start.x = dragInfo.start.y = -1;
\r
4959 dragInfo.from = dragInfo.start;
\r
4960 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4964 case WM_LBUTTONUP:
\r
4966 if (fromX == -1) break;
\r
4967 if (x == fromX && y == fromY) {
\r
4968 dragInfo.from.x = dragInfo.from.y = -1;
\r
4969 /* Upclick on same square */
\r
4971 /* Clicked same square twice: abort click-click move */
\r
4972 fromX = fromY = -1;
\r
4974 ClearPremoveHighlights();
\r
4976 /* First square clicked: start click-click move */
\r
4977 SetHighlights(fromX, fromY, -1, -1);
\r
4979 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4980 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4981 /* Errant click; ignore */
\r
4984 /* Finish drag move. */
\r
4985 if (appData.debugMode) {
\r
4986 fprintf(debugFP, "release\n");
\r
4988 dragInfo.from.x = dragInfo.from.y = -1;
\r
4991 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4992 appData.animate = appData.animate && !appData.animateDragging;
\r
4993 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4994 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4995 fromX = fromY = -1;
\r
4996 ClearHighlights();
\r
4997 DrawPosition(FALSE, boards[currentMove]);
\r
5000 if(moveType != ImpossibleMove) {
\r
5001 /* [HGM] use move type to determine if move is promotion.
\r
5002 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5003 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5004 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5005 appData.alwaysPromoteToQueen)
\r
5006 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5008 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5009 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5010 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5011 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5012 // kludge to temporarily execute move on display, wthout promotng yet
\r
5013 promotionChoice = TRUE;
\r
5014 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5015 boards[currentMove][toY][toX] = p;
\r
5016 DrawPosition(FALSE, boards[currentMove]);
\r
5017 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5018 boards[currentMove][toY][toX] = q;
\r
5021 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5022 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5024 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5025 appData.animate = saveAnimate;
\r
5026 fromX = fromY = -1;
\r
5027 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5028 ClearHighlights();
\r
5030 if (appData.animate || appData.animateDragging ||
\r
5031 appData.highlightDragging || gotPremove) {
\r
5032 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5035 dragInfo.start.x = dragInfo.start.y = -1;
\r
5036 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5039 case WM_MOUSEMOVE:
\r
5040 if ((appData.animateDragging || appData.highlightDragging)
\r
5041 && (wParam & MK_LBUTTON)
\r
5042 && dragInfo.from.x >= 0)
\r
5044 BOOL full_repaint = FALSE;
\r
5046 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5047 if (appData.animateDragging) {
\r
5048 dragInfo.pos = pt;
\r
5050 if (appData.highlightDragging) {
\r
5051 SetHighlights(fromX, fromY, x, y);
\r
5052 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5053 full_repaint = TRUE;
\r
5057 DrawPosition( full_repaint, NULL);
\r
5059 dragInfo.lastpos = dragInfo.pos;
\r
5063 case WM_MOUSEWHEEL: // [DM]
\r
5064 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5065 /* Mouse Wheel is being rolled forward
\r
5066 * Play moves forward
\r
5068 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5069 if(lastDir == 1) ForwardEvent(); else lastDir = 1; // [HGM] suppress first event in each direction
\r
5070 /* Mouse Wheel is being rolled backward
\r
5071 * Play moves backward
\r
5073 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5074 if(lastDir == -1) BackwardEvent(); else lastDir = -1;
\r
5078 case WM_MBUTTONDOWN:
\r
5079 case WM_RBUTTONDOWN:
\r
5082 fromX = fromY = -1;
\r
5083 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5084 dragInfo.start.x = dragInfo.start.y = -1;
\r
5085 dragInfo.from = dragInfo.start;
\r
5086 dragInfo.lastpos = dragInfo.pos;
\r
5087 if (appData.highlightDragging) {
\r
5088 ClearHighlights();
\r
5091 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5092 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5093 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5094 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5095 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5098 DrawPosition(TRUE, NULL);
\r
5100 switch (gameMode) {
\r
5101 case EditPosition:
\r
5102 case IcsExamining:
\r
5103 if (x < 0 || y < 0) break;
\r
5106 if (message == WM_MBUTTONDOWN) {
\r
5107 buttonCount = 3; /* even if system didn't think so */
\r
5108 if (wParam & MK_SHIFT)
\r
5109 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5111 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5112 } else { /* message == WM_RBUTTONDOWN */
\r
5114 if (buttonCount == 3) {
\r
5115 if (wParam & MK_SHIFT)
\r
5116 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5118 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5120 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5123 /* Just have one menu, on the right button. Windows users don't
\r
5124 think to try the middle one, and sometimes other software steals
\r
5125 it, or it doesn't really exist. */
\r
5126 if(gameInfo.variant != VariantShogi)
\r
5127 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5129 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5133 case IcsPlayingWhite:
\r
5134 case IcsPlayingBlack:
\r
5136 case MachinePlaysWhite:
\r
5137 case MachinePlaysBlack:
\r
5138 if (appData.testLegality &&
\r
5139 gameInfo.variant != VariantBughouse &&
\r
5140 gameInfo.variant != VariantCrazyhouse) break;
\r
5141 if (x < 0 || y < 0) break;
\r
5144 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5145 SetupDropMenu(hmenu);
\r
5146 MenuPopup(hwnd, pt, hmenu, -1);
\r
5157 /* Preprocess messages for buttons in main window */
\r
5159 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5161 int id = GetWindowLong(hwnd, GWL_ID);
\r
5164 for (i=0; i<N_BUTTONS; i++) {
\r
5165 if (buttonDesc[i].id == id) break;
\r
5167 if (i == N_BUTTONS) return 0;
\r
5168 switch (message) {
\r
5173 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5174 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5181 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5184 if (appData.icsActive) {
\r
5185 if (GetKeyState(VK_SHIFT) < 0) {
\r
5187 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5188 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5192 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5193 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5200 if (appData.icsActive) {
\r
5201 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5202 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5204 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5206 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5207 PopUpMoveDialog((char)wParam);
\r
5213 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5216 /* Process messages for Promotion dialog box */
\r
5218 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5222 switch (message) {
\r
5223 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5224 /* Center the dialog over the application window */
\r
5225 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5226 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5227 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5228 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5229 SW_SHOW : SW_HIDE);
\r
5230 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5231 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5232 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5233 PieceToChar(WhiteAngel) != '~' ||
\r
5234 PieceToChar(BlackAngel) >= 'A' &&
\r
5235 PieceToChar(BlackAngel) != '~' ) ?
\r
5236 SW_SHOW : SW_HIDE);
\r
5237 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5238 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5239 PieceToChar(WhiteMarshall) != '~' ||
\r
5240 PieceToChar(BlackMarshall) >= 'A' &&
\r
5241 PieceToChar(BlackMarshall) != '~' ) ?
\r
5242 SW_SHOW : SW_HIDE);
\r
5243 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5244 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5245 gameInfo.variant != VariantShogi ?
\r
5246 SW_SHOW : SW_HIDE);
\r
5247 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5248 gameInfo.variant != VariantShogi ?
\r
5249 SW_SHOW : SW_HIDE);
\r
5250 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5251 gameInfo.variant == VariantShogi ?
\r
5252 SW_SHOW : SW_HIDE);
\r
5253 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5254 gameInfo.variant == VariantShogi ?
\r
5255 SW_SHOW : SW_HIDE);
\r
5256 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5257 gameInfo.variant == VariantSuper ?
\r
5258 SW_SHOW : SW_HIDE);
\r
5261 case WM_COMMAND: /* message: received a command */
\r
5262 switch (LOWORD(wParam)) {
\r
5264 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5265 ClearHighlights();
\r
5266 DrawPosition(FALSE, NULL);
\r
5269 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5272 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5275 promoChar = PieceToChar(BlackRook);
\r
5278 promoChar = PieceToChar(BlackBishop);
\r
5280 case PB_Chancellor:
\r
5281 promoChar = PieceToChar(BlackMarshall);
\r
5283 case PB_Archbishop:
\r
5284 promoChar = PieceToChar(BlackAngel);
\r
5287 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5292 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5293 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5294 only show the popup when we are already sure the move is valid or
\r
5295 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5296 will figure out it is a promotion from the promoChar. */
\r
5297 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5298 if (!appData.highlightLastMove) {
\r
5299 ClearHighlights();
\r
5300 DrawPosition(FALSE, NULL);
\r
5307 /* Pop up promotion dialog */
\r
5309 PromotionPopup(HWND hwnd)
\r
5313 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5314 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5315 hwnd, (DLGPROC)lpProc);
\r
5316 FreeProcInstance(lpProc);
\r
5319 /* Toggle ShowThinking */
\r
5321 ToggleShowThinking()
\r
5323 appData.showThinking = !appData.showThinking;
\r
5324 ShowThinkingEvent();
\r
5328 LoadGameDialog(HWND hwnd, char* title)
\r
5332 char fileTitle[MSG_SIZ];
\r
5333 f = OpenFileDialog(hwnd, "rb", "",
\r
5334 appData.oldSaveStyle ? "gam" : "pgn",
\r
5336 title, &number, fileTitle, NULL);
\r
5338 cmailMsgLoaded = FALSE;
\r
5339 if (number == 0) {
\r
5340 int error = GameListBuild(f);
\r
5342 DisplayError("Cannot build game list", error);
\r
5343 } else if (!ListEmpty(&gameList) &&
\r
5344 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5345 GameListPopUp(f, fileTitle);
\r
5348 GameListDestroy();
\r
5351 LoadGame(f, number, fileTitle, FALSE);
\r
5356 ChangedConsoleFont()
\r
5359 CHARRANGE tmpsel, sel;
\r
5360 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5361 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5362 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5365 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5366 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5367 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5368 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5369 * size. This was undocumented in the version of MSVC++ that I had
\r
5370 * when I wrote the code, but is apparently documented now.
\r
5372 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5373 cfmt.bCharSet = f->lf.lfCharSet;
\r
5374 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5375 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5376 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5377 /* Why are the following seemingly needed too? */
\r
5378 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5379 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5380 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5382 tmpsel.cpMax = -1; /*999999?*/
\r
5383 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5384 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5385 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5386 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5388 paraf.cbSize = sizeof(paraf);
\r
5389 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5390 paraf.dxStartIndent = 0;
\r
5391 paraf.dxOffset = WRAP_INDENT;
\r
5392 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5393 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5396 /*---------------------------------------------------------------------------*\
\r
5398 * Window Proc for main window
\r
5400 \*---------------------------------------------------------------------------*/
\r
5402 /* Process messages for main window, etc. */
\r
5404 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5407 int wmId, wmEvent;
\r
5411 char fileTitle[MSG_SIZ];
\r
5412 char buf[MSG_SIZ];
\r
5413 static SnapData sd;
\r
5415 switch (message) {
\r
5417 case WM_PAINT: /* message: repaint portion of window */
\r
5421 case WM_ERASEBKGND:
\r
5422 if (IsIconic(hwnd)) {
\r
5423 /* Cheat; change the message */
\r
5424 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5426 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5430 case WM_LBUTTONDOWN:
\r
5431 case WM_MBUTTONDOWN:
\r
5432 case WM_RBUTTONDOWN:
\r
5433 case WM_LBUTTONUP:
\r
5434 case WM_MBUTTONUP:
\r
5435 case WM_RBUTTONUP:
\r
5436 case WM_MOUSEMOVE:
\r
5437 case WM_MOUSEWHEEL:
\r
5438 MouseEvent(hwnd, message, wParam, lParam);
\r
5443 if (appData.icsActive) {
\r
5444 if (wParam == '\t') {
\r
5445 if (GetKeyState(VK_SHIFT) < 0) {
\r
5447 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5448 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5452 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5453 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5457 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5458 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5460 SendMessage(h, message, wParam, lParam);
\r
5462 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5463 PopUpMoveDialog((char)wParam);
\r
5467 case WM_PALETTECHANGED:
\r
5468 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5470 HDC hdc = GetDC(hwndMain);
\r
5471 SelectPalette(hdc, hPal, TRUE);
\r
5472 nnew = RealizePalette(hdc);
\r
5474 paletteChanged = TRUE;
\r
5476 UpdateColors(hdc);
\r
5478 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5481 ReleaseDC(hwnd, hdc);
\r
5485 case WM_QUERYNEWPALETTE:
\r
5486 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5488 HDC hdc = GetDC(hwndMain);
\r
5489 paletteChanged = FALSE;
\r
5490 SelectPalette(hdc, hPal, FALSE);
\r
5491 nnew = RealizePalette(hdc);
\r
5493 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5495 ReleaseDC(hwnd, hdc);
\r
5500 case WM_COMMAND: /* message: command from application menu */
\r
5501 wmId = LOWORD(wParam);
\r
5502 wmEvent = HIWORD(wParam);
\r
5507 AnalysisPopDown();
\r
5510 case IDM_NewGameFRC:
\r
5511 if( NewGameFRC() == 0 ) {
\r
5513 AnalysisPopDown();
\r
5517 case IDM_NewVariant:
\r
5518 NewVariantPopup(hwnd);
\r
5521 case IDM_LoadGame:
\r
5522 LoadGameDialog(hwnd, "Load Game from File");
\r
5525 case IDM_LoadNextGame:
\r
5529 case IDM_LoadPrevGame:
\r
5533 case IDM_ReloadGame:
\r
5537 case IDM_LoadPosition:
\r
5538 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5539 Reset(FALSE, TRUE);
\r
5542 f = OpenFileDialog(hwnd, "rb", "",
\r
5543 appData.oldSaveStyle ? "pos" : "fen",
\r
5545 "Load Position from File", &number, fileTitle, NULL);
\r
5547 LoadPosition(f, number, fileTitle);
\r
5551 case IDM_LoadNextPosition:
\r
5552 ReloadPosition(1);
\r
5555 case IDM_LoadPrevPosition:
\r
5556 ReloadPosition(-1);
\r
5559 case IDM_ReloadPosition:
\r
5560 ReloadPosition(0);
\r
5563 case IDM_SaveGame:
\r
5564 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5565 f = OpenFileDialog(hwnd, "a", defName,
\r
5566 appData.oldSaveStyle ? "gam" : "pgn",
\r
5568 "Save Game to File", NULL, fileTitle, NULL);
\r
5570 SaveGame(f, 0, "");
\r
5574 case IDM_SavePosition:
\r
5575 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5576 f = OpenFileDialog(hwnd, "a", defName,
\r
5577 appData.oldSaveStyle ? "pos" : "fen",
\r
5579 "Save Position to File", NULL, fileTitle, NULL);
\r
5581 SavePosition(f, 0, "");
\r
5585 case IDM_SaveDiagram:
\r
5586 defName = "diagram";
\r
5587 f = OpenFileDialog(hwnd, "wb", defName,
\r
5590 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5596 case IDM_CopyGame:
\r
5597 CopyGameToClipboard();
\r
5600 case IDM_PasteGame:
\r
5601 PasteGameFromClipboard();
\r
5604 case IDM_CopyGameListToClipboard:
\r
5605 CopyGameListToClipboard();
\r
5608 /* [AS] Autodetect FEN or PGN data */
\r
5609 case IDM_PasteAny:
\r
5610 PasteGameOrFENFromClipboard();
\r
5613 /* [AS] Move history */
\r
5614 case IDM_ShowMoveHistory:
\r
5615 if( MoveHistoryIsUp() ) {
\r
5616 MoveHistoryPopDown();
\r
5619 MoveHistoryPopUp();
\r
5623 /* [AS] Eval graph */
\r
5624 case IDM_ShowEvalGraph:
\r
5625 if( EvalGraphIsUp() ) {
\r
5626 EvalGraphPopDown();
\r
5633 /* [AS] Engine output */
\r
5634 case IDM_ShowEngineOutput:
\r
5635 if( EngineOutputIsUp() ) {
\r
5636 EngineOutputPopDown();
\r
5639 EngineOutputPopUp();
\r
5643 /* [AS] User adjudication */
\r
5644 case IDM_UserAdjudication_White:
\r
5645 UserAdjudicationEvent( +1 );
\r
5648 case IDM_UserAdjudication_Black:
\r
5649 UserAdjudicationEvent( -1 );
\r
5652 case IDM_UserAdjudication_Draw:
\r
5653 UserAdjudicationEvent( 0 );
\r
5656 /* [AS] Game list options dialog */
\r
5657 case IDM_GameListOptions:
\r
5658 GameListOptions();
\r
5661 case IDM_CopyPosition:
\r
5662 CopyFENToClipboard();
\r
5665 case IDM_PastePosition:
\r
5666 PasteFENFromClipboard();
\r
5669 case IDM_MailMove:
\r
5673 case IDM_ReloadCMailMsg:
\r
5674 Reset(TRUE, TRUE);
\r
5675 ReloadCmailMsgEvent(FALSE);
\r
5678 case IDM_Minimize:
\r
5679 ShowWindow(hwnd, SW_MINIMIZE);
\r
5686 case IDM_MachineWhite:
\r
5687 MachineWhiteEvent();
\r
5689 * refresh the tags dialog only if it's visible
\r
5691 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5693 tags = PGNTags(&gameInfo);
\r
5694 TagsPopUp(tags, CmailMsg());
\r
5699 case IDM_MachineBlack:
\r
5700 MachineBlackEvent();
\r
5702 * refresh the tags dialog only if it's visible
\r
5704 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5706 tags = PGNTags(&gameInfo);
\r
5707 TagsPopUp(tags, CmailMsg());
\r
5712 case IDM_TwoMachines:
\r
5713 TwoMachinesEvent();
\r
5715 * refresh the tags dialog only if it's visible
\r
5717 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5719 tags = PGNTags(&gameInfo);
\r
5720 TagsPopUp(tags, CmailMsg());
\r
5725 case IDM_AnalysisMode:
\r
5726 if (!first.analysisSupport) {
\r
5727 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5728 DisplayError(buf, 0);
\r
5730 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5731 if (appData.icsActive) {
\r
5732 if (gameMode != IcsObserving) {
\r
5733 sprintf(buf, "You are not observing a game");
\r
5734 DisplayError(buf, 0);
\r
5735 /* secure check */
\r
5736 if (appData.icsEngineAnalyze) {
\r
5737 if (appData.debugMode)
\r
5738 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5739 ExitAnalyzeMode();
\r
5745 /* if enable, user want disable icsEngineAnalyze */
\r
5746 if (appData.icsEngineAnalyze) {
\r
5747 ExitAnalyzeMode();
\r
5751 appData.icsEngineAnalyze = TRUE;
\r
5752 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5755 if (!appData.showThinking) ToggleShowThinking();
\r
5756 AnalyzeModeEvent();
\r
5760 case IDM_AnalyzeFile:
\r
5761 if (!first.analysisSupport) {
\r
5762 char buf[MSG_SIZ];
\r
5763 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5764 DisplayError(buf, 0);
\r
5766 if (!appData.showThinking) ToggleShowThinking();
\r
5767 AnalyzeFileEvent();
\r
5768 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5769 AnalysisPeriodicEvent(1);
\r
5773 case IDM_IcsClient:
\r
5777 case IDM_EditGame:
\r
5781 case IDM_EditPosition:
\r
5782 EditPositionEvent();
\r
5785 case IDM_Training:
\r
5789 case IDM_ShowGameList:
\r
5790 ShowGameListProc();
\r
5793 case IDM_EditTags:
\r
5797 case IDM_EditComment:
\r
5798 if (commentDialogUp && editComment) {
\r
5801 EditCommentEvent();
\r
5821 case IDM_CallFlag:
\r
5841 case IDM_StopObserving:
\r
5842 StopObservingEvent();
\r
5845 case IDM_StopExamining:
\r
5846 StopExaminingEvent();
\r
5849 case IDM_TypeInMove:
\r
5850 PopUpMoveDialog('\000');
\r
5853 case IDM_TypeInName:
\r
5854 PopUpNameDialog('\000');
\r
5857 case IDM_Backward:
\r
5859 SetFocus(hwndMain);
\r
5864 SetFocus(hwndMain);
\r
5869 SetFocus(hwndMain);
\r
5874 SetFocus(hwndMain);
\r
5881 case IDM_TruncateGame:
\r
5882 TruncateGameEvent();
\r
5889 case IDM_RetractMove:
\r
5890 RetractMoveEvent();
\r
5893 case IDM_FlipView:
\r
5894 flipView = !flipView;
\r
5895 DrawPosition(FALSE, NULL);
\r
5898 case IDM_FlipClock:
\r
5899 flipClock = !flipClock;
\r
5900 DisplayBothClocks();
\r
5903 case IDM_GeneralOptions:
\r
5904 GeneralOptionsPopup(hwnd);
\r
5905 DrawPosition(TRUE, NULL);
\r
5908 case IDM_BoardOptions:
\r
5909 BoardOptionsPopup(hwnd);
\r
5912 case IDM_EnginePlayOptions:
\r
5913 EnginePlayOptionsPopup(hwnd);
\r
5916 case IDM_OptionsUCI:
\r
5917 UciOptionsPopup(hwnd);
\r
5920 case IDM_IcsOptions:
\r
5921 IcsOptionsPopup(hwnd);
\r
5925 FontsOptionsPopup(hwnd);
\r
5929 SoundOptionsPopup(hwnd);
\r
5932 case IDM_CommPort:
\r
5933 CommPortOptionsPopup(hwnd);
\r
5936 case IDM_LoadOptions:
\r
5937 LoadOptionsPopup(hwnd);
\r
5940 case IDM_SaveOptions:
\r
5941 SaveOptionsPopup(hwnd);
\r
5944 case IDM_TimeControl:
\r
5945 TimeControlOptionsPopup(hwnd);
\r
5948 case IDM_SaveSettings:
\r
5949 SaveSettings(settingsFileName);
\r
5952 case IDM_SaveSettingsOnExit:
\r
5953 saveSettingsOnExit = !saveSettingsOnExit;
\r
5954 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5955 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5956 MF_CHECKED : MF_UNCHECKED));
\r
5967 case IDM_AboutGame:
\r
5972 appData.debugMode = !appData.debugMode;
\r
5973 if (appData.debugMode) {
\r
5974 char dir[MSG_SIZ];
\r
5975 GetCurrentDirectory(MSG_SIZ, dir);
\r
5976 SetCurrentDirectory(installDir);
\r
5977 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5978 SetCurrentDirectory(dir);
\r
5979 setbuf(debugFP, NULL);
\r
5986 case IDM_HELPCONTENTS:
\r
5987 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5988 MessageBox (GetFocus(),
\r
5989 "Unable to activate help",
\r
5990 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5994 case IDM_HELPSEARCH:
\r
5995 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5996 MessageBox (GetFocus(),
\r
5997 "Unable to activate help",
\r
5998 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6002 case IDM_HELPHELP:
\r
6003 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6004 MessageBox (GetFocus(),
\r
6005 "Unable to activate help",
\r
6006 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6011 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6013 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6014 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6015 FreeProcInstance(lpProc);
\r
6018 case IDM_DirectCommand1:
\r
6019 AskQuestionEvent("Direct Command",
\r
6020 "Send to chess program:", "", "1");
\r
6022 case IDM_DirectCommand2:
\r
6023 AskQuestionEvent("Direct Command",
\r
6024 "Send to second chess program:", "", "2");
\r
6027 case EP_WhitePawn:
\r
6028 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6029 fromX = fromY = -1;
\r
6032 case EP_WhiteKnight:
\r
6033 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6034 fromX = fromY = -1;
\r
6037 case EP_WhiteBishop:
\r
6038 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6039 fromX = fromY = -1;
\r
6042 case EP_WhiteRook:
\r
6043 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6044 fromX = fromY = -1;
\r
6047 case EP_WhiteQueen:
\r
6048 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6049 fromX = fromY = -1;
\r
6052 case EP_WhiteFerz:
\r
6053 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6054 fromX = fromY = -1;
\r
6057 case EP_WhiteWazir:
\r
6058 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6059 fromX = fromY = -1;
\r
6062 case EP_WhiteAlfil:
\r
6063 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6064 fromX = fromY = -1;
\r
6067 case EP_WhiteCannon:
\r
6068 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6069 fromX = fromY = -1;
\r
6072 case EP_WhiteCardinal:
\r
6073 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6074 fromX = fromY = -1;
\r
6077 case EP_WhiteMarshall:
\r
6078 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6079 fromX = fromY = -1;
\r
6082 case EP_WhiteKing:
\r
6083 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6084 fromX = fromY = -1;
\r
6087 case EP_BlackPawn:
\r
6088 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6089 fromX = fromY = -1;
\r
6092 case EP_BlackKnight:
\r
6093 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6094 fromX = fromY = -1;
\r
6097 case EP_BlackBishop:
\r
6098 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6099 fromX = fromY = -1;
\r
6102 case EP_BlackRook:
\r
6103 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6104 fromX = fromY = -1;
\r
6107 case EP_BlackQueen:
\r
6108 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6109 fromX = fromY = -1;
\r
6112 case EP_BlackFerz:
\r
6113 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6114 fromX = fromY = -1;
\r
6117 case EP_BlackWazir:
\r
6118 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6119 fromX = fromY = -1;
\r
6122 case EP_BlackAlfil:
\r
6123 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6124 fromX = fromY = -1;
\r
6127 case EP_BlackCannon:
\r
6128 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6129 fromX = fromY = -1;
\r
6132 case EP_BlackCardinal:
\r
6133 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6134 fromX = fromY = -1;
\r
6137 case EP_BlackMarshall:
\r
6138 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6139 fromX = fromY = -1;
\r
6142 case EP_BlackKing:
\r
6143 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6144 fromX = fromY = -1;
\r
6147 case EP_EmptySquare:
\r
6148 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6149 fromX = fromY = -1;
\r
6152 case EP_ClearBoard:
\r
6153 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6154 fromX = fromY = -1;
\r
6158 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6159 fromX = fromY = -1;
\r
6163 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6164 fromX = fromY = -1;
\r
6168 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6169 fromX = fromY = -1;
\r
6173 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6174 fromX = fromY = -1;
\r
6178 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6179 fromX = fromY = -1;
\r
6183 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6184 fromX = fromY = -1;
\r
6188 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6189 fromX = fromY = -1;
\r
6193 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6194 fromX = fromY = -1;
\r
6198 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6199 fromX = fromY = -1;
\r
6203 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6209 case CLOCK_TIMER_ID:
\r
6210 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6211 clockTimerEvent = 0;
\r
6212 DecrementClocks(); /* call into back end */
\r
6214 case LOAD_GAME_TIMER_ID:
\r
6215 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6216 loadGameTimerEvent = 0;
\r
6217 AutoPlayGameLoop(); /* call into back end */
\r
6219 case ANALYSIS_TIMER_ID:
\r
6220 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6221 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6222 AnalysisPeriodicEvent(0);
\r
6224 KillTimer(hwnd, analysisTimerEvent);
\r
6225 analysisTimerEvent = 0;
\r
6228 case DELAYED_TIMER_ID:
\r
6229 KillTimer(hwnd, delayedTimerEvent);
\r
6230 delayedTimerEvent = 0;
\r
6231 delayedTimerCallback();
\r
6236 case WM_USER_Input:
\r
6237 InputEvent(hwnd, message, wParam, lParam);
\r
6240 /* [AS] Also move "attached" child windows */
\r
6241 case WM_WINDOWPOSCHANGING:
\r
6242 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6243 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6245 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6246 /* Window is moving */
\r
6249 GetWindowRect( hwnd, &rcMain );
\r
6251 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6252 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6253 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6258 /* [AS] Snapping */
\r
6259 case WM_ENTERSIZEMOVE:
\r
6260 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6261 if (hwnd == hwndMain) {
\r
6262 doingSizing = TRUE;
\r
6265 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6269 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6270 if (hwnd == hwndMain) {
\r
6271 lastSizing = wParam;
\r
6276 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6277 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6279 case WM_EXITSIZEMOVE:
\r
6280 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6281 if (hwnd == hwndMain) {
\r
6283 doingSizing = FALSE;
\r
6284 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6285 GetClientRect(hwnd, &client);
\r
6286 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6288 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6290 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6293 case WM_DESTROY: /* message: window being destroyed */
\r
6294 PostQuitMessage(0);
\r
6298 if (hwnd == hwndMain) {
\r
6303 default: /* Passes it on if unprocessed */
\r
6304 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6309 /*---------------------------------------------------------------------------*\
\r
6311 * Misc utility routines
\r
6313 \*---------------------------------------------------------------------------*/
\r
6316 * Decent random number generator, at least not as bad as Windows
\r
6317 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6319 unsigned int randstate;
\r
6324 randstate = randstate * 1664525 + 1013904223;
\r
6325 return (int) randstate & 0x7fffffff;
\r
6329 mysrandom(unsigned int seed)
\r
6336 * returns TRUE if user selects a different color, FALSE otherwise
\r
6340 ChangeColor(HWND hwnd, COLORREF *which)
\r
6342 static BOOL firstTime = TRUE;
\r
6343 static DWORD customColors[16];
\r
6345 COLORREF newcolor;
\r
6350 /* Make initial colors in use available as custom colors */
\r
6351 /* Should we put the compiled-in defaults here instead? */
\r
6353 customColors[i++] = lightSquareColor & 0xffffff;
\r
6354 customColors[i++] = darkSquareColor & 0xffffff;
\r
6355 customColors[i++] = whitePieceColor & 0xffffff;
\r
6356 customColors[i++] = blackPieceColor & 0xffffff;
\r
6357 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6358 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6360 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6361 customColors[i++] = textAttribs[ccl].color;
\r
6363 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6364 firstTime = FALSE;
\r
6367 cc.lStructSize = sizeof(cc);
\r
6368 cc.hwndOwner = hwnd;
\r
6369 cc.hInstance = NULL;
\r
6370 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6371 cc.lpCustColors = (LPDWORD) customColors;
\r
6372 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6374 if (!ChooseColor(&cc)) return FALSE;
\r
6376 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6377 if (newcolor == *which) return FALSE;
\r
6378 *which = newcolor;
\r
6382 InitDrawingColors();
\r
6383 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6388 MyLoadSound(MySound *ms)
\r
6394 if (ms->data) free(ms->data);
\r
6397 switch (ms->name[0]) {
\r
6403 /* System sound from Control Panel. Don't preload here. */
\r
6407 if (ms->name[1] == NULLCHAR) {
\r
6408 /* "!" alone = silence */
\r
6411 /* Builtin wave resource. Error if not found. */
\r
6412 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6413 if (h == NULL) break;
\r
6414 ms->data = (void *)LoadResource(hInst, h);
\r
6415 if (h == NULL) break;
\r
6420 /* .wav file. Error if not found. */
\r
6421 f = fopen(ms->name, "rb");
\r
6422 if (f == NULL) break;
\r
6423 if (fstat(fileno(f), &st) < 0) break;
\r
6424 ms->data = malloc(st.st_size);
\r
6425 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6431 char buf[MSG_SIZ];
\r
6432 sprintf(buf, "Error loading sound %s", ms->name);
\r
6433 DisplayError(buf, GetLastError());
\r
6439 MyPlaySound(MySound *ms)
\r
6441 BOOLEAN ok = FALSE;
\r
6442 switch (ms->name[0]) {
\r
6448 /* System sound from Control Panel (deprecated feature).
\r
6449 "$" alone or an unset sound name gets default beep (still in use). */
\r
6450 if (ms->name[1]) {
\r
6451 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6453 if (!ok) ok = MessageBeep(MB_OK);
\r
6456 /* Builtin wave resource, or "!" alone for silence */
\r
6457 if (ms->name[1]) {
\r
6458 if (ms->data == NULL) return FALSE;
\r
6459 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6465 /* .wav file. Error if not found. */
\r
6466 if (ms->data == NULL) return FALSE;
\r
6467 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6470 /* Don't print an error: this can happen innocently if the sound driver
\r
6471 is busy; for instance, if another instance of WinBoard is playing
\r
6472 a sound at about the same time. */
\r
6475 char buf[MSG_SIZ];
\r
6476 sprintf(buf, "Error playing sound %s", ms->name);
\r
6477 DisplayError(buf, GetLastError());
\r
6485 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6488 OPENFILENAME *ofn;
\r
6489 static UINT *number; /* gross that this is static */
\r
6491 switch (message) {
\r
6492 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6493 /* Center the dialog over the application window */
\r
6494 ofn = (OPENFILENAME *) lParam;
\r
6495 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6496 number = (UINT *) ofn->lCustData;
\r
6497 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6501 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6502 return FALSE; /* Allow for further processing */
\r
6505 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6506 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6508 return FALSE; /* Allow for further processing */
\r
6514 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6516 static UINT *number;
\r
6517 OPENFILENAME *ofname;
\r
6520 case WM_INITDIALOG:
\r
6521 ofname = (OPENFILENAME *)lParam;
\r
6522 number = (UINT *)(ofname->lCustData);
\r
6525 ofnot = (OFNOTIFY *)lParam;
\r
6526 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6527 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6536 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6537 char *nameFilt, char *dlgTitle, UINT *number,
\r
6538 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6540 OPENFILENAME openFileName;
\r
6541 char buf1[MSG_SIZ];
\r
6544 if (fileName == NULL) fileName = buf1;
\r
6545 if (defName == NULL) {
\r
6546 strcpy(fileName, "*.");
\r
6547 strcat(fileName, defExt);
\r
6549 strcpy(fileName, defName);
\r
6551 if (fileTitle) strcpy(fileTitle, "");
\r
6552 if (number) *number = 0;
\r
6554 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6555 openFileName.hwndOwner = hwnd;
\r
6556 openFileName.hInstance = (HANDLE) hInst;
\r
6557 openFileName.lpstrFilter = nameFilt;
\r
6558 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6559 openFileName.nMaxCustFilter = 0L;
\r
6560 openFileName.nFilterIndex = 1L;
\r
6561 openFileName.lpstrFile = fileName;
\r
6562 openFileName.nMaxFile = MSG_SIZ;
\r
6563 openFileName.lpstrFileTitle = fileTitle;
\r
6564 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6565 openFileName.lpstrInitialDir = NULL;
\r
6566 openFileName.lpstrTitle = dlgTitle;
\r
6567 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6568 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6569 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6570 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6571 openFileName.nFileOffset = 0;
\r
6572 openFileName.nFileExtension = 0;
\r
6573 openFileName.lpstrDefExt = defExt;
\r
6574 openFileName.lCustData = (LONG) number;
\r
6575 openFileName.lpfnHook = oldDialog ?
\r
6576 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6577 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6579 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6580 GetOpenFileName(&openFileName)) {
\r
6581 /* open the file */
\r
6582 f = fopen(openFileName.lpstrFile, write);
\r
6584 MessageBox(hwnd, "File open failed", NULL,
\r
6585 MB_OK|MB_ICONEXCLAMATION);
\r
6589 int err = CommDlgExtendedError();
\r
6590 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6599 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6601 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6604 * Get the first pop-up menu in the menu template. This is the
\r
6605 * menu that TrackPopupMenu displays.
\r
6607 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6609 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6612 * TrackPopup uses screen coordinates, so convert the
\r
6613 * coordinates of the mouse click to screen coordinates.
\r
6615 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6617 /* Draw and track the floating pop-up menu. */
\r
6618 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6619 pt.x, pt.y, 0, hwnd, NULL);
\r
6621 /* Destroy the menu.*/
\r
6622 DestroyMenu(hmenu);
\r
6627 int sizeX, sizeY, newSizeX, newSizeY;
\r
6629 } ResizeEditPlusButtonsClosure;
\r
6632 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6634 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6638 if (hChild == cl->hText) return TRUE;
\r
6639 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6640 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6641 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6642 ScreenToClient(cl->hDlg, &pt);
\r
6643 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6644 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6648 /* Resize a dialog that has a (rich) edit field filling most of
\r
6649 the top, with a row of buttons below */
\r
6651 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6654 int newTextHeight, newTextWidth;
\r
6655 ResizeEditPlusButtonsClosure cl;
\r
6657 /*if (IsIconic(hDlg)) return;*/
\r
6658 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6660 cl.hdwp = BeginDeferWindowPos(8);
\r
6662 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6663 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6664 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6665 if (newTextHeight < 0) {
\r
6666 newSizeY += -newTextHeight;
\r
6667 newTextHeight = 0;
\r
6669 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6670 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6676 cl.newSizeX = newSizeX;
\r
6677 cl.newSizeY = newSizeY;
\r
6678 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6680 EndDeferWindowPos(cl.hdwp);
\r
6683 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6685 RECT rChild, rParent;
\r
6686 int wChild, hChild, wParent, hParent;
\r
6687 int wScreen, hScreen, xNew, yNew;
\r
6690 /* Get the Height and Width of the child window */
\r
6691 GetWindowRect (hwndChild, &rChild);
\r
6692 wChild = rChild.right - rChild.left;
\r
6693 hChild = rChild.bottom - rChild.top;
\r
6695 /* Get the Height and Width of the parent window */
\r
6696 GetWindowRect (hwndParent, &rParent);
\r
6697 wParent = rParent.right - rParent.left;
\r
6698 hParent = rParent.bottom - rParent.top;
\r
6700 /* Get the display limits */
\r
6701 hdc = GetDC (hwndChild);
\r
6702 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6703 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6704 ReleaseDC(hwndChild, hdc);
\r
6706 /* Calculate new X position, then adjust for screen */
\r
6707 xNew = rParent.left + ((wParent - wChild) /2);
\r
6710 } else if ((xNew+wChild) > wScreen) {
\r
6711 xNew = wScreen - wChild;
\r
6714 /* Calculate new Y position, then adjust for screen */
\r
6716 yNew = rParent.top + ((hParent - hChild) /2);
\r
6719 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6724 } else if ((yNew+hChild) > hScreen) {
\r
6725 yNew = hScreen - hChild;
\r
6728 /* Set it, and return */
\r
6729 return SetWindowPos (hwndChild, NULL,
\r
6730 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6733 /* Center one window over another */
\r
6734 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6736 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6739 /*---------------------------------------------------------------------------*\
\r
6741 * Startup Dialog functions
\r
6743 \*---------------------------------------------------------------------------*/
\r
6745 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6747 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6749 while (*cd != NULL) {
\r
6750 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6756 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6758 char buf1[ARG_MAX];
\r
6761 if (str[0] == '@') {
\r
6762 FILE* f = fopen(str + 1, "r");
\r
6764 DisplayFatalError(str + 1, errno, 2);
\r
6767 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6769 buf1[len] = NULLCHAR;
\r
6773 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6776 char buf[MSG_SIZ];
\r
6777 char *end = strchr(str, '\n');
\r
6778 if (end == NULL) return;
\r
6779 memcpy(buf, str, end - str);
\r
6780 buf[end - str] = NULLCHAR;
\r
6781 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6787 SetStartupDialogEnables(HWND hDlg)
\r
6789 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6790 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6791 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6792 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6793 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6794 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6795 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6796 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6797 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6798 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6799 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6800 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6801 IsDlgButtonChecked(hDlg, OPT_View));
\r
6805 QuoteForFilename(char *filename)
\r
6807 int dquote, space;
\r
6808 dquote = strchr(filename, '"') != NULL;
\r
6809 space = strchr(filename, ' ') != NULL;
\r
6810 if (dquote || space) {
\r
6822 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6824 char buf[MSG_SIZ];
\r
6827 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6828 q = QuoteForFilename(nthcp);
\r
6829 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6830 if (*nthdir != NULLCHAR) {
\r
6831 q = QuoteForFilename(nthdir);
\r
6832 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6834 if (*nthcp == NULLCHAR) {
\r
6835 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6836 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6837 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6838 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6843 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6845 char buf[MSG_SIZ];
\r
6849 switch (message) {
\r
6850 case WM_INITDIALOG:
\r
6851 /* Center the dialog */
\r
6852 CenterWindow (hDlg, GetDesktopWindow());
\r
6853 /* Initialize the dialog items */
\r
6854 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6855 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6856 firstChessProgramNames);
\r
6857 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6858 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6859 secondChessProgramNames);
\r
6860 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6861 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6862 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6863 if (*appData.icsHelper != NULLCHAR) {
\r
6864 char *q = QuoteForFilename(appData.icsHelper);
\r
6865 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6867 if (*appData.icsHost == NULLCHAR) {
\r
6868 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6869 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6870 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6871 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6872 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6875 if (appData.icsActive) {
\r
6876 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6878 else if (appData.noChessProgram) {
\r
6879 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6882 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6885 SetStartupDialogEnables(hDlg);
\r
6889 switch (LOWORD(wParam)) {
\r
6891 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6892 strcpy(buf, "/fcp=");
\r
6893 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6895 ParseArgs(StringGet, &p);
\r
6896 strcpy(buf, "/scp=");
\r
6897 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6899 ParseArgs(StringGet, &p);
\r
6900 appData.noChessProgram = FALSE;
\r
6901 appData.icsActive = FALSE;
\r
6902 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6903 strcpy(buf, "/ics /icshost=");
\r
6904 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6906 ParseArgs(StringGet, &p);
\r
6907 if (appData.zippyPlay) {
\r
6908 strcpy(buf, "/fcp=");
\r
6909 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6911 ParseArgs(StringGet, &p);
\r
6913 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6914 appData.noChessProgram = TRUE;
\r
6915 appData.icsActive = FALSE;
\r
6917 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6918 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6921 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6922 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6924 ParseArgs(StringGet, &p);
\r
6926 EndDialog(hDlg, TRUE);
\r
6933 case IDM_HELPCONTENTS:
\r
6934 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6935 MessageBox (GetFocus(),
\r
6936 "Unable to activate help",
\r
6937 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6942 SetStartupDialogEnables(hDlg);
\r
6950 /*---------------------------------------------------------------------------*\
\r
6952 * About box dialog functions
\r
6954 \*---------------------------------------------------------------------------*/
\r
6956 /* Process messages for "About" dialog box */
\r
6958 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6960 switch (message) {
\r
6961 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6962 /* Center the dialog over the application window */
\r
6963 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6964 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6967 case WM_COMMAND: /* message: received a command */
\r
6968 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6969 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6970 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6978 /*---------------------------------------------------------------------------*\
\r
6980 * Comment Dialog functions
\r
6982 \*---------------------------------------------------------------------------*/
\r
6985 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6987 static HANDLE hwndText = NULL;
\r
6988 int len, newSizeX, newSizeY, flags;
\r
6989 static int sizeX, sizeY;
\r
6994 switch (message) {
\r
6995 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6996 /* Initialize the dialog items */
\r
6997 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6998 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6999 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7000 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7001 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7002 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7003 SetWindowText(hDlg, commentTitle);
\r
7004 if (editComment) {
\r
7005 SetFocus(hwndText);
\r
7007 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7009 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7010 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7011 MAKELPARAM(FALSE, 0));
\r
7012 /* Size and position the dialog */
\r
7013 if (!commentDialog) {
\r
7014 commentDialog = hDlg;
\r
7015 flags = SWP_NOZORDER;
\r
7016 GetClientRect(hDlg, &rect);
\r
7017 sizeX = rect.right;
\r
7018 sizeY = rect.bottom;
\r
7019 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7020 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7021 WINDOWPLACEMENT wp;
\r
7022 EnsureOnScreen(&commentX, &commentY);
\r
7023 wp.length = sizeof(WINDOWPLACEMENT);
\r
7025 wp.showCmd = SW_SHOW;
\r
7026 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7027 wp.rcNormalPosition.left = commentX;
\r
7028 wp.rcNormalPosition.right = commentX + commentW;
\r
7029 wp.rcNormalPosition.top = commentY;
\r
7030 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7031 SetWindowPlacement(hDlg, &wp);
\r
7033 GetClientRect(hDlg, &rect);
\r
7034 newSizeX = rect.right;
\r
7035 newSizeY = rect.bottom;
\r
7036 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7037 newSizeX, newSizeY);
\r
7044 case WM_COMMAND: /* message: received a command */
\r
7045 switch (LOWORD(wParam)) {
\r
7047 if (editComment) {
\r
7049 /* Read changed options from the dialog box */
\r
7050 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7051 len = GetWindowTextLength(hwndText);
\r
7052 str = (char *) malloc(len + 1);
\r
7053 GetWindowText(hwndText, str, len + 1);
\r
7062 ReplaceComment(commentIndex, str);
\r
7069 case OPT_CancelComment:
\r
7073 case OPT_ClearComment:
\r
7074 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7077 case OPT_EditComment:
\r
7078 EditCommentEvent();
\r
7087 newSizeX = LOWORD(lParam);
\r
7088 newSizeY = HIWORD(lParam);
\r
7089 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7094 case WM_GETMINMAXINFO:
\r
7095 /* Prevent resizing window too small */
\r
7096 mmi = (MINMAXINFO *) lParam;
\r
7097 mmi->ptMinTrackSize.x = 100;
\r
7098 mmi->ptMinTrackSize.y = 100;
\r
7105 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7110 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7112 if (str == NULL) str = "";
\r
7113 p = (char *) malloc(2 * strlen(str) + 2);
\r
7116 if (*str == '\n') *q++ = '\r';
\r
7120 if (commentText != NULL) free(commentText);
\r
7122 commentIndex = index;
\r
7123 commentTitle = title;
\r
7125 editComment = edit;
\r
7127 if (commentDialog) {
\r
7128 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7129 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7131 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7132 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7133 hwndMain, (DLGPROC)lpProc);
\r
7134 FreeProcInstance(lpProc);
\r
7136 commentDialogUp = TRUE;
\r
7140 /*---------------------------------------------------------------------------*\
\r
7142 * Type-in move dialog functions
\r
7144 \*---------------------------------------------------------------------------*/
\r
7147 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7149 char move[MSG_SIZ];
\r
7151 ChessMove moveType;
\r
7152 int fromX, fromY, toX, toY;
\r
7155 switch (message) {
\r
7156 case WM_INITDIALOG:
\r
7157 move[0] = (char) lParam;
\r
7158 move[1] = NULLCHAR;
\r
7159 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7160 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7161 SetWindowText(hInput, move);
\r
7163 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7167 switch (LOWORD(wParam)) {
\r
7169 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7170 gameMode != Training) {
\r
7171 DisplayMoveError("Displayed move is not current");
\r
7173 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7174 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7175 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7176 if (gameMode != Training)
\r
7177 forwardMostMove = currentMove;
\r
7178 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7180 DisplayMoveError("Could not parse move");
\r
7183 EndDialog(hDlg, TRUE);
\r
7186 EndDialog(hDlg, FALSE);
\r
7197 PopUpMoveDialog(char firstchar)
\r
7201 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7202 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7203 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7204 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7205 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7206 gameMode == Training) {
\r
7207 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7208 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7209 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7210 FreeProcInstance(lpProc);
\r
7214 /*---------------------------------------------------------------------------*\
\r
7216 * Type-in name dialog functions
\r
7218 \*---------------------------------------------------------------------------*/
\r
7221 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7223 char move[MSG_SIZ];
\r
7226 switch (message) {
\r
7227 case WM_INITDIALOG:
\r
7228 move[0] = (char) lParam;
\r
7229 move[1] = NULLCHAR;
\r
7230 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7231 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7232 SetWindowText(hInput, move);
\r
7234 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7238 switch (LOWORD(wParam)) {
\r
7240 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7241 appData.userName = strdup(move);
\r
7243 EndDialog(hDlg, TRUE);
\r
7246 EndDialog(hDlg, FALSE);
\r
7257 PopUpNameDialog(char firstchar)
\r
7261 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7262 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7263 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7264 FreeProcInstance(lpProc);
\r
7267 /*---------------------------------------------------------------------------*\
\r
7271 \*---------------------------------------------------------------------------*/
\r
7273 /* Nonmodal error box */
\r
7274 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7275 WPARAM wParam, LPARAM lParam);
\r
7278 ErrorPopUp(char *title, char *content)
\r
7282 BOOLEAN modal = hwndMain == NULL;
\r
7300 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7301 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7304 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7306 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7307 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7308 hwndMain, (DLGPROC)lpProc);
\r
7309 FreeProcInstance(lpProc);
\r
7316 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7317 if (errorDialog == NULL) return;
\r
7318 DestroyWindow(errorDialog);
\r
7319 errorDialog = NULL;
\r
7323 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7328 switch (message) {
\r
7329 case WM_INITDIALOG:
\r
7330 GetWindowRect(hDlg, &rChild);
\r
7333 SetWindowPos(hDlg, NULL, rChild.left,
\r
7334 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7335 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7339 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7340 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7341 and it doesn't work when you resize the dialog.
\r
7342 For now, just give it a default position.
\r
7344 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7346 errorDialog = hDlg;
\r
7347 SetWindowText(hDlg, errorTitle);
\r
7348 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7349 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7353 switch (LOWORD(wParam)) {
\r
7356 if (errorDialog == hDlg) errorDialog = NULL;
\r
7357 DestroyWindow(hDlg);
\r
7369 HWND gothicDialog = NULL;
\r
7372 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7376 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7378 switch (message) {
\r
7379 case WM_INITDIALOG:
\r
7380 GetWindowRect(hDlg, &rChild);
\r
7382 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7386 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7387 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7388 and it doesn't work when you resize the dialog.
\r
7389 For now, just give it a default position.
\r
7391 gothicDialog = hDlg;
\r
7392 SetWindowText(hDlg, errorTitle);
\r
7393 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7394 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7398 switch (LOWORD(wParam)) {
\r
7401 if (errorDialog == hDlg) errorDialog = NULL;
\r
7402 DestroyWindow(hDlg);
\r
7414 GothicPopUp(char *title, VariantClass variant)
\r
7418 BOOLEAN modal = hwndMain == NULL;
\r
7419 static char *lastTitle;
\r
7421 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7422 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7424 if(lastTitle != title && gothicDialog != NULL) {
\r
7425 DestroyWindow(gothicDialog);
\r
7426 gothicDialog = NULL;
\r
7428 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7429 title = lastTitle;
\r
7430 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7431 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7432 hwndMain, (DLGPROC)lpProc);
\r
7433 FreeProcInstance(lpProc);
\r
7438 /*---------------------------------------------------------------------------*\
\r
7440 * Ics Interaction console functions
\r
7442 \*---------------------------------------------------------------------------*/
\r
7444 #define HISTORY_SIZE 64
\r
7445 static char *history[HISTORY_SIZE];
\r
7446 int histIn = 0, histP = 0;
\r
7449 SaveInHistory(char *cmd)
\r
7451 if (history[histIn] != NULL) {
\r
7452 free(history[histIn]);
\r
7453 history[histIn] = NULL;
\r
7455 if (*cmd == NULLCHAR) return;
\r
7456 history[histIn] = StrSave(cmd);
\r
7457 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7458 if (history[histIn] != NULL) {
\r
7459 free(history[histIn]);
\r
7460 history[histIn] = NULL;
\r
7466 PrevInHistory(char *cmd)
\r
7469 if (histP == histIn) {
\r
7470 if (history[histIn] != NULL) free(history[histIn]);
\r
7471 history[histIn] = StrSave(cmd);
\r
7473 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7474 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7476 return history[histP];
\r
7482 if (histP == histIn) return NULL;
\r
7483 histP = (histP + 1) % HISTORY_SIZE;
\r
7484 return history[histP];
\r
7491 BOOLEAN immediate;
\r
7492 } IcsTextMenuEntry;
\r
7493 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7494 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7497 ParseIcsTextMenu(char *icsTextMenuString)
\r
7500 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7501 char *p = icsTextMenuString;
\r
7502 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7505 if (e->command != NULL) {
\r
7507 e->command = NULL;
\r
7511 e = icsTextMenuEntry;
\r
7512 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7513 if (*p == ';' || *p == '\n') {
\r
7514 e->item = strdup("-");
\r
7515 e->command = NULL;
\r
7517 } else if (*p == '-') {
\r
7518 e->item = strdup("-");
\r
7519 e->command = NULL;
\r
7523 char *q, *r, *s, *t;
\r
7525 q = strchr(p, ',');
\r
7526 if (q == NULL) break;
\r
7528 r = strchr(q + 1, ',');
\r
7529 if (r == NULL) break;
\r
7531 s = strchr(r + 1, ',');
\r
7532 if (s == NULL) break;
\r
7535 t = strchr(s + 1, c);
\r
7538 t = strchr(s + 1, c);
\r
7540 if (t != NULL) *t = NULLCHAR;
\r
7541 e->item = strdup(p);
\r
7542 e->command = strdup(q + 1);
\r
7543 e->getname = *(r + 1) != '0';
\r
7544 e->immediate = *(s + 1) != '0';
\r
7548 if (t == NULL) break;
\r
7557 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7561 hmenu = LoadMenu(hInst, "TextMenu");
\r
7562 h = GetSubMenu(hmenu, 0);
\r
7564 if (strcmp(e->item, "-") == 0) {
\r
7565 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7567 if (e->item[0] == '|') {
\r
7568 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7569 IDM_CommandX + i, &e->item[1]);
\r
7571 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7580 WNDPROC consoleTextWindowProc;
\r
7583 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7585 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7586 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7590 SetWindowText(hInput, command);
\r
7592 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7594 sel.cpMin = 999999;
\r
7595 sel.cpMax = 999999;
\r
7596 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7601 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7602 if (sel.cpMin == sel.cpMax) {
\r
7603 /* Expand to surrounding word */
\r
7606 tr.chrg.cpMax = sel.cpMin;
\r
7607 tr.chrg.cpMin = --sel.cpMin;
\r
7608 if (sel.cpMin < 0) break;
\r
7609 tr.lpstrText = name;
\r
7610 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7611 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7615 tr.chrg.cpMin = sel.cpMax;
\r
7616 tr.chrg.cpMax = ++sel.cpMax;
\r
7617 tr.lpstrText = name;
\r
7618 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7619 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7622 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7623 MessageBeep(MB_ICONEXCLAMATION);
\r
7627 tr.lpstrText = name;
\r
7628 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7630 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7631 MessageBeep(MB_ICONEXCLAMATION);
\r
7634 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7637 sprintf(buf, "%s %s", command, name);
\r
7638 SetWindowText(hInput, buf);
\r
7639 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7641 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7642 SetWindowText(hInput, buf);
\r
7643 sel.cpMin = 999999;
\r
7644 sel.cpMax = 999999;
\r
7645 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7651 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7656 switch (message) {
\r
7658 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7661 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7664 sel.cpMin = 999999;
\r
7665 sel.cpMax = 999999;
\r
7666 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7667 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7672 if (wParam == '\t') {
\r
7673 if (GetKeyState(VK_SHIFT) < 0) {
\r
7675 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7676 if (buttonDesc[0].hwnd) {
\r
7677 SetFocus(buttonDesc[0].hwnd);
\r
7679 SetFocus(hwndMain);
\r
7683 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7686 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7688 SendMessage(hInput, message, wParam, lParam);
\r
7692 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7694 return SendMessage(hInput, message, wParam, lParam);
\r
7695 case WM_MBUTTONDOWN:
\r
7696 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7697 case WM_RBUTTONDOWN:
\r
7698 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7699 /* Move selection here if it was empty */
\r
7701 pt.x = LOWORD(lParam);
\r
7702 pt.y = HIWORD(lParam);
\r
7703 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7704 if (sel.cpMin == sel.cpMax) {
\r
7705 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7706 sel.cpMax = sel.cpMin;
\r
7707 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7709 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7712 case WM_RBUTTONUP:
\r
7713 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7714 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7715 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7718 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7719 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7720 if (sel.cpMin == sel.cpMax) {
\r
7721 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7722 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7724 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7725 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7727 pt.x = LOWORD(lParam);
\r
7728 pt.y = HIWORD(lParam);
\r
7729 MenuPopup(hwnd, pt, hmenu, -1);
\r
7733 switch (LOWORD(wParam)) {
\r
7734 case IDM_QuickPaste:
\r
7736 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7737 if (sel.cpMin == sel.cpMax) {
\r
7738 MessageBeep(MB_ICONEXCLAMATION);
\r
7741 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7742 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7743 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7748 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7751 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7754 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7758 int i = LOWORD(wParam) - IDM_CommandX;
\r
7759 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7760 icsTextMenuEntry[i].command != NULL) {
\r
7761 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7762 icsTextMenuEntry[i].getname,
\r
7763 icsTextMenuEntry[i].immediate);
\r
7771 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7774 WNDPROC consoleInputWindowProc;
\r
7777 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7779 char buf[MSG_SIZ];
\r
7781 static BOOL sendNextChar = FALSE;
\r
7782 static BOOL quoteNextChar = FALSE;
\r
7783 InputSource *is = consoleInputSource;
\r
7787 switch (message) {
\r
7789 if (!appData.localLineEditing || sendNextChar) {
\r
7790 is->buf[0] = (CHAR) wParam;
\r
7792 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7793 sendNextChar = FALSE;
\r
7796 if (quoteNextChar) {
\r
7797 buf[0] = (char) wParam;
\r
7798 buf[1] = NULLCHAR;
\r
7799 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7800 quoteNextChar = FALSE;
\r
7804 case '\r': /* Enter key */
\r
7805 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7806 if (consoleEcho) SaveInHistory(is->buf);
\r
7807 is->buf[is->count++] = '\n';
\r
7808 is->buf[is->count] = NULLCHAR;
\r
7809 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7810 if (consoleEcho) {
\r
7811 ConsoleOutput(is->buf, is->count, TRUE);
\r
7812 } else if (appData.localLineEditing) {
\r
7813 ConsoleOutput("\n", 1, TRUE);
\r
7816 case '\033': /* Escape key */
\r
7817 SetWindowText(hwnd, "");
\r
7818 cf.cbSize = sizeof(CHARFORMAT);
\r
7819 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7820 if (consoleEcho) {
\r
7821 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7823 cf.crTextColor = COLOR_ECHOOFF;
\r
7825 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7826 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7828 case '\t': /* Tab key */
\r
7829 if (GetKeyState(VK_SHIFT) < 0) {
\r
7831 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7834 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7835 if (buttonDesc[0].hwnd) {
\r
7836 SetFocus(buttonDesc[0].hwnd);
\r
7838 SetFocus(hwndMain);
\r
7842 case '\023': /* Ctrl+S */
\r
7843 sendNextChar = TRUE;
\r
7845 case '\021': /* Ctrl+Q */
\r
7846 quoteNextChar = TRUE;
\r
7855 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7856 p = PrevInHistory(buf);
\r
7858 SetWindowText(hwnd, p);
\r
7859 sel.cpMin = 999999;
\r
7860 sel.cpMax = 999999;
\r
7861 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7866 p = NextInHistory();
\r
7868 SetWindowText(hwnd, p);
\r
7869 sel.cpMin = 999999;
\r
7870 sel.cpMax = 999999;
\r
7871 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7877 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7881 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7885 case WM_MBUTTONDOWN:
\r
7886 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7887 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7889 case WM_RBUTTONUP:
\r
7890 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7891 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7892 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7896 hmenu = LoadMenu(hInst, "InputMenu");
\r
7897 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7898 if (sel.cpMin == sel.cpMax) {
\r
7899 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7900 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7902 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7903 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7905 pt.x = LOWORD(lParam);
\r
7906 pt.y = HIWORD(lParam);
\r
7907 MenuPopup(hwnd, pt, hmenu, -1);
\r
7911 switch (LOWORD(wParam)) {
\r
7913 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7915 case IDM_SelectAll:
\r
7917 sel.cpMax = -1; /*999999?*/
\r
7918 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7921 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7924 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7927 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7932 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7935 #define CO_MAX 100000
\r
7936 #define CO_TRIM 1000
\r
7939 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7941 static SnapData sd;
\r
7942 static HWND hText, hInput, hFocus;
\r
7943 InputSource *is = consoleInputSource;
\r
7945 static int sizeX, sizeY;
\r
7946 int newSizeX, newSizeY;
\r
7949 switch (message) {
\r
7950 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7951 hwndConsole = hDlg;
\r
7952 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7953 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7955 consoleTextWindowProc = (WNDPROC)
\r
7956 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7957 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7958 consoleInputWindowProc = (WNDPROC)
\r
7959 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7960 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7961 Colorize(ColorNormal, TRUE);
\r
7962 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7963 ChangedConsoleFont();
\r
7964 GetClientRect(hDlg, &rect);
\r
7965 sizeX = rect.right;
\r
7966 sizeY = rect.bottom;
\r
7967 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7968 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7969 WINDOWPLACEMENT wp;
\r
7970 EnsureOnScreen(&consoleX, &consoleY);
\r
7971 wp.length = sizeof(WINDOWPLACEMENT);
\r
7973 wp.showCmd = SW_SHOW;
\r
7974 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7975 wp.rcNormalPosition.left = consoleX;
\r
7976 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7977 wp.rcNormalPosition.top = consoleY;
\r
7978 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7979 SetWindowPlacement(hDlg, &wp);
\r
7982 // [HGM] Chessknight's change 2004-07-13
\r
7983 else { /* Determine Defaults */
\r
7984 WINDOWPLACEMENT wp;
\r
7985 consoleX = winWidth + 1;
\r
7986 consoleY = boardY;
\r
7987 consoleW = screenWidth - winWidth;
\r
7988 consoleH = winHeight;
\r
7989 EnsureOnScreen(&consoleX, &consoleY);
\r
7990 wp.length = sizeof(WINDOWPLACEMENT);
\r
7992 wp.showCmd = SW_SHOW;
\r
7993 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7994 wp.rcNormalPosition.left = consoleX;
\r
7995 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7996 wp.rcNormalPosition.top = consoleY;
\r
7997 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7998 SetWindowPlacement(hDlg, &wp);
\r
8013 if (IsIconic(hDlg)) break;
\r
8014 newSizeX = LOWORD(lParam);
\r
8015 newSizeY = HIWORD(lParam);
\r
8016 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8017 RECT rectText, rectInput;
\r
8019 int newTextHeight, newTextWidth;
\r
8020 GetWindowRect(hText, &rectText);
\r
8021 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8022 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8023 if (newTextHeight < 0) {
\r
8024 newSizeY += -newTextHeight;
\r
8025 newTextHeight = 0;
\r
8027 SetWindowPos(hText, NULL, 0, 0,
\r
8028 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8029 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8030 pt.x = rectInput.left;
\r
8031 pt.y = rectInput.top + newSizeY - sizeY;
\r
8032 ScreenToClient(hDlg, &pt);
\r
8033 SetWindowPos(hInput, NULL,
\r
8034 pt.x, pt.y, /* needs client coords */
\r
8035 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8036 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8042 case WM_GETMINMAXINFO:
\r
8043 /* Prevent resizing window too small */
\r
8044 mmi = (MINMAXINFO *) lParam;
\r
8045 mmi->ptMinTrackSize.x = 100;
\r
8046 mmi->ptMinTrackSize.y = 100;
\r
8049 /* [AS] Snapping */
\r
8050 case WM_ENTERSIZEMOVE:
\r
8051 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8054 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8057 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8059 case WM_EXITSIZEMOVE:
\r
8060 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8063 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8071 if (hwndConsole) return;
\r
8072 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8073 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8078 ConsoleOutput(char* data, int length, int forceVisible)
\r
8083 char buf[CO_MAX+1];
\r
8086 static int delayLF = 0;
\r
8087 CHARRANGE savesel, sel;
\r
8089 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8097 while (length--) {
\r
8105 } else if (*p == '\007') {
\r
8106 MyPlaySound(&sounds[(int)SoundBell]);
\r
8113 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8114 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8115 /* Save current selection */
\r
8116 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8117 exlen = GetWindowTextLength(hText);
\r
8118 /* Find out whether current end of text is visible */
\r
8119 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8120 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8121 /* Trim existing text if it's too long */
\r
8122 if (exlen + (q - buf) > CO_MAX) {
\r
8123 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8126 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8127 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8129 savesel.cpMin -= trim;
\r
8130 savesel.cpMax -= trim;
\r
8131 if (exlen < 0) exlen = 0;
\r
8132 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8133 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8135 /* Append the new text */
\r
8136 sel.cpMin = exlen;
\r
8137 sel.cpMax = exlen;
\r
8138 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8139 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8140 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8141 if (forceVisible || exlen == 0 ||
\r
8142 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8143 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8144 /* Scroll to make new end of text visible if old end of text
\r
8145 was visible or new text is an echo of user typein */
\r
8146 sel.cpMin = 9999999;
\r
8147 sel.cpMax = 9999999;
\r
8148 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8149 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8150 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8151 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8153 if (savesel.cpMax == exlen || forceVisible) {
\r
8154 /* Move insert point to new end of text if it was at the old
\r
8155 end of text or if the new text is an echo of user typein */
\r
8156 sel.cpMin = 9999999;
\r
8157 sel.cpMax = 9999999;
\r
8158 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8160 /* Restore previous selection */
\r
8161 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8163 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8170 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8174 COLORREF oldFg, oldBg;
\r
8178 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8180 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8181 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8182 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8185 rect.right = x + squareSize;
\r
8187 rect.bottom = y + squareSize;
\r
8190 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8191 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8192 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8193 &rect, str, strlen(str), NULL);
\r
8195 (void) SetTextColor(hdc, oldFg);
\r
8196 (void) SetBkColor(hdc, oldBg);
\r
8197 (void) SelectObject(hdc, oldFont);
\r
8201 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8202 RECT *rect, char *color, char *flagFell)
\r
8206 COLORREF oldFg, oldBg;
\r
8209 if (appData.clockMode) {
\r
8211 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8213 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8220 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8221 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8223 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8224 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8226 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8228 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8229 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8230 rect, str, strlen(str), NULL);
\r
8232 (void) SetTextColor(hdc, oldFg);
\r
8233 (void) SetBkColor(hdc, oldBg);
\r
8234 (void) SelectObject(hdc, oldFont);
\r
8239 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8245 if( count <= 0 ) {
\r
8246 if (appData.debugMode) {
\r
8247 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8250 return ERROR_INVALID_USER_BUFFER;
\r
8253 ResetEvent(ovl->hEvent);
\r
8254 ovl->Offset = ovl->OffsetHigh = 0;
\r
8255 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8259 err = GetLastError();
\r
8260 if (err == ERROR_IO_PENDING) {
\r
8261 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8265 err = GetLastError();
\r
8272 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8277 ResetEvent(ovl->hEvent);
\r
8278 ovl->Offset = ovl->OffsetHigh = 0;
\r
8279 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8283 err = GetLastError();
\r
8284 if (err == ERROR_IO_PENDING) {
\r
8285 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8289 err = GetLastError();
\r
8295 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8296 void CheckForInputBufferFull( InputSource * is )
\r
8298 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8299 /* Look for end of line */
\r
8300 char * p = is->buf;
\r
8302 while( p < is->next && *p != '\n' ) {
\r
8306 if( p >= is->next ) {
\r
8307 if (appData.debugMode) {
\r
8308 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8311 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8312 is->count = (DWORD) -1;
\r
8313 is->next = is->buf;
\r
8319 InputThread(LPVOID arg)
\r
8324 is = (InputSource *) arg;
\r
8325 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8326 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8327 while (is->hThread != NULL) {
\r
8328 is->error = DoReadFile(is->hFile, is->next,
\r
8329 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8330 &is->count, &ovl);
\r
8331 if (is->error == NO_ERROR) {
\r
8332 is->next += is->count;
\r
8334 if (is->error == ERROR_BROKEN_PIPE) {
\r
8335 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8338 is->count = (DWORD) -1;
\r
8339 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8344 CheckForInputBufferFull( is );
\r
8346 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8348 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8350 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8353 CloseHandle(ovl.hEvent);
\r
8354 CloseHandle(is->hFile);
\r
8356 if (appData.debugMode) {
\r
8357 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8364 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8366 NonOvlInputThread(LPVOID arg)
\r
8373 is = (InputSource *) arg;
\r
8374 while (is->hThread != NULL) {
\r
8375 is->error = ReadFile(is->hFile, is->next,
\r
8376 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8377 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8378 if (is->error == NO_ERROR) {
\r
8379 /* Change CRLF to LF */
\r
8380 if (is->next > is->buf) {
\r
8382 i = is->count + 1;
\r
8390 if (prev == '\r' && *p == '\n') {
\r
8402 if (is->error == ERROR_BROKEN_PIPE) {
\r
8403 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8406 is->count = (DWORD) -1;
\r
8410 CheckForInputBufferFull( is );
\r
8412 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8414 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8416 if (is->count < 0) break; /* Quit on error */
\r
8418 CloseHandle(is->hFile);
\r
8423 SocketInputThread(LPVOID arg)
\r
8427 is = (InputSource *) arg;
\r
8428 while (is->hThread != NULL) {
\r
8429 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8430 if ((int)is->count == SOCKET_ERROR) {
\r
8431 is->count = (DWORD) -1;
\r
8432 is->error = WSAGetLastError();
\r
8434 is->error = NO_ERROR;
\r
8435 is->next += is->count;
\r
8436 if (is->count == 0 && is->second == is) {
\r
8437 /* End of file on stderr; quit with no message */
\r
8441 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8443 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8445 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8451 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8455 is = (InputSource *) lParam;
\r
8456 if (is->lineByLine) {
\r
8457 /* Feed in lines one by one */
\r
8458 char *p = is->buf;
\r
8460 while (q < is->next) {
\r
8461 if (*q++ == '\n') {
\r
8462 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8467 /* Move any partial line to the start of the buffer */
\r
8469 while (p < is->next) {
\r
8474 if (is->error != NO_ERROR || is->count == 0) {
\r
8475 /* Notify backend of the error. Note: If there was a partial
\r
8476 line at the end, it is not flushed through. */
\r
8477 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8480 /* Feed in the whole chunk of input at once */
\r
8481 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8482 is->next = is->buf;
\r
8486 /*---------------------------------------------------------------------------*\
\r
8488 * Menu enables. Used when setting various modes.
\r
8490 \*---------------------------------------------------------------------------*/
\r
8498 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8500 while (enab->item > 0) {
\r
8501 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8506 Enables gnuEnables[] = {
\r
8507 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8516 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8520 Enables icsEnables[] = {
\r
8521 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8522 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8523 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8527 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8532 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8537 Enables zippyEnables[] = {
\r
8538 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8539 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8540 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8545 Enables ncpEnables[] = {
\r
8546 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8555 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8564 Enables trainingOnEnables[] = {
\r
8565 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8576 Enables trainingOffEnables[] = {
\r
8577 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8578 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8579 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8580 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8581 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8582 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8583 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8584 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8588 /* These modify either ncpEnables or gnuEnables */
\r
8589 Enables cmailEnables[] = {
\r
8590 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8591 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8592 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8593 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8595 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8600 Enables machineThinkingEnables[] = {
\r
8601 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8619 Enables userThinkingEnables[] = {
\r
8620 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8638 /*---------------------------------------------------------------------------*\
\r
8640 * Front-end interface functions exported by XBoard.
\r
8641 * Functions appear in same order as prototypes in frontend.h.
\r
8643 \*---------------------------------------------------------------------------*/
\r
8647 static UINT prevChecked = 0;
\r
8648 static int prevPausing = 0;
\r
8651 if (pausing != prevPausing) {
\r
8652 prevPausing = pausing;
\r
8653 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8654 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8655 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8658 switch (gameMode) {
\r
8659 case BeginningOfGame:
\r
8660 if (appData.icsActive)
\r
8661 nowChecked = IDM_IcsClient;
\r
8662 else if (appData.noChessProgram)
\r
8663 nowChecked = IDM_EditGame;
\r
8665 nowChecked = IDM_MachineBlack;
\r
8667 case MachinePlaysBlack:
\r
8668 nowChecked = IDM_MachineBlack;
\r
8670 case MachinePlaysWhite:
\r
8671 nowChecked = IDM_MachineWhite;
\r
8673 case TwoMachinesPlay:
\r
8674 nowChecked = IDM_TwoMachines;
\r
8677 nowChecked = IDM_AnalysisMode;
\r
8680 nowChecked = IDM_AnalyzeFile;
\r
8683 nowChecked = IDM_EditGame;
\r
8685 case PlayFromGameFile:
\r
8686 nowChecked = IDM_LoadGame;
\r
8688 case EditPosition:
\r
8689 nowChecked = IDM_EditPosition;
\r
8692 nowChecked = IDM_Training;
\r
8694 case IcsPlayingWhite:
\r
8695 case IcsPlayingBlack:
\r
8696 case IcsObserving:
\r
8698 nowChecked = IDM_IcsClient;
\r
8705 if (prevChecked != 0)
\r
8706 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8707 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8708 if (nowChecked != 0)
\r
8709 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8710 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8712 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8713 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8714 MF_BYCOMMAND|MF_ENABLED);
\r
8716 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8717 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8720 prevChecked = nowChecked;
\r
8722 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8723 if (appData.icsActive) {
\r
8724 if (appData.icsEngineAnalyze) {
\r
8725 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8726 MF_BYCOMMAND|MF_CHECKED);
\r
8728 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8729 MF_BYCOMMAND|MF_UNCHECKED);
\r
8737 HMENU hmenu = GetMenu(hwndMain);
\r
8738 SetMenuEnables(hmenu, icsEnables);
\r
8739 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8740 MF_BYPOSITION|MF_ENABLED);
\r
8742 if (appData.zippyPlay) {
\r
8743 SetMenuEnables(hmenu, zippyEnables);
\r
8744 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8745 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8746 MF_BYCOMMAND|MF_ENABLED);
\r
8754 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8760 HMENU hmenu = GetMenu(hwndMain);
\r
8761 SetMenuEnables(hmenu, ncpEnables);
\r
8762 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8763 MF_BYPOSITION|MF_GRAYED);
\r
8764 DrawMenuBar(hwndMain);
\r
8770 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8774 SetTrainingModeOn()
\r
8777 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8778 for (i = 0; i < N_BUTTONS; i++) {
\r
8779 if (buttonDesc[i].hwnd != NULL)
\r
8780 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8785 VOID SetTrainingModeOff()
\r
8788 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8789 for (i = 0; i < N_BUTTONS; i++) {
\r
8790 if (buttonDesc[i].hwnd != NULL)
\r
8791 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8797 SetUserThinkingEnables()
\r
8799 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8803 SetMachineThinkingEnables()
\r
8805 HMENU hMenu = GetMenu(hwndMain);
\r
8806 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8808 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8810 if (gameMode == MachinePlaysBlack) {
\r
8811 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8812 } else if (gameMode == MachinePlaysWhite) {
\r
8813 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8814 } else if (gameMode == TwoMachinesPlay) {
\r
8815 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8821 DisplayTitle(char *str)
\r
8823 char title[MSG_SIZ], *host;
\r
8824 if (str[0] != NULLCHAR) {
\r
8825 strcpy(title, str);
\r
8826 } else if (appData.icsActive) {
\r
8827 if (appData.icsCommPort[0] != NULLCHAR)
\r
8830 host = appData.icsHost;
\r
8831 sprintf(title, "%s: %s", szTitle, host);
\r
8832 } else if (appData.noChessProgram) {
\r
8833 strcpy(title, szTitle);
\r
8835 strcpy(title, szTitle);
\r
8836 strcat(title, ": ");
\r
8837 strcat(title, first.tidy);
\r
8839 SetWindowText(hwndMain, title);
\r
8844 DisplayMessage(char *str1, char *str2)
\r
8848 int remain = MESSAGE_TEXT_MAX - 1;
\r
8851 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8852 messageText[0] = NULLCHAR;
\r
8854 len = strlen(str1);
\r
8855 if (len > remain) len = remain;
\r
8856 strncpy(messageText, str1, len);
\r
8857 messageText[len] = NULLCHAR;
\r
8860 if (*str2 && remain >= 2) {
\r
8862 strcat(messageText, " ");
\r
8865 len = strlen(str2);
\r
8866 if (len > remain) len = remain;
\r
8867 strncat(messageText, str2, len);
\r
8869 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8871 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8872 hdc = GetDC(hwndMain);
\r
8873 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8874 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8875 &messageRect, messageText, strlen(messageText), NULL);
\r
8876 (void) SelectObject(hdc, oldFont);
\r
8877 (void) ReleaseDC(hwndMain, hdc);
\r
8881 DisplayError(char *str, int error)
\r
8883 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8889 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8890 NULL, error, LANG_NEUTRAL,
\r
8891 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8893 sprintf(buf, "%s:\n%s", str, buf2);
\r
8895 ErrorMap *em = errmap;
\r
8896 while (em->err != 0 && em->err != error) em++;
\r
8897 if (em->err != 0) {
\r
8898 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8900 sprintf(buf, "%s:\nError code %d", str, error);
\r
8905 ErrorPopUp("Error", buf);
\r
8910 DisplayMoveError(char *str)
\r
8912 fromX = fromY = -1;
\r
8913 ClearHighlights();
\r
8914 DrawPosition(FALSE, NULL);
\r
8915 if (appData.popupMoveErrors) {
\r
8916 ErrorPopUp("Error", str);
\r
8918 DisplayMessage(str, "");
\r
8919 moveErrorMessageUp = TRUE;
\r
8924 DisplayFatalError(char *str, int error, int exitStatus)
\r
8926 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8928 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8931 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8932 NULL, error, LANG_NEUTRAL,
\r
8933 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8935 sprintf(buf, "%s:\n%s", str, buf2);
\r
8937 ErrorMap *em = errmap;
\r
8938 while (em->err != 0 && em->err != error) em++;
\r
8939 if (em->err != 0) {
\r
8940 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8942 sprintf(buf, "%s:\nError code %d", str, error);
\r
8947 if (appData.debugMode) {
\r
8948 fprintf(debugFP, "%s: %s\n", label, str);
\r
8950 if (appData.popupExitMessage) {
\r
8951 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8952 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8954 ExitEvent(exitStatus);
\r
8959 DisplayInformation(char *str)
\r
8961 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8966 DisplayNote(char *str)
\r
8968 ErrorPopUp("Note", str);
\r
8973 char *title, *question, *replyPrefix;
\r
8978 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8980 static QuestionParams *qp;
\r
8981 char reply[MSG_SIZ];
\r
8984 switch (message) {
\r
8985 case WM_INITDIALOG:
\r
8986 qp = (QuestionParams *) lParam;
\r
8987 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8988 SetWindowText(hDlg, qp->title);
\r
8989 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8990 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8994 switch (LOWORD(wParam)) {
\r
8996 strcpy(reply, qp->replyPrefix);
\r
8997 if (*reply) strcat(reply, " ");
\r
8998 len = strlen(reply);
\r
8999 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9000 strcat(reply, "\n");
\r
9001 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9002 EndDialog(hDlg, TRUE);
\r
9003 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9006 EndDialog(hDlg, FALSE);
\r
9017 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9019 QuestionParams qp;
\r
9023 qp.question = question;
\r
9024 qp.replyPrefix = replyPrefix;
\r
9026 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9027 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9028 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9029 FreeProcInstance(lpProc);
\r
9032 /* [AS] Pick FRC position */
\r
9033 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9035 static int * lpIndexFRC;
\r
9041 case WM_INITDIALOG:
\r
9042 lpIndexFRC = (int *) lParam;
\r
9044 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9046 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9047 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9048 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9049 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9054 switch( LOWORD(wParam) ) {
\r
9056 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9057 EndDialog( hDlg, 0 );
\r
9058 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9061 EndDialog( hDlg, 1 );
\r
9063 case IDC_NFG_Edit:
\r
9064 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9065 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9067 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9070 case IDC_NFG_Random:
\r
9071 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9072 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9085 int index = appData.defaultFrcPosition;
\r
9086 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9088 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9090 if( result == 0 ) {
\r
9091 appData.defaultFrcPosition = index;
\r
9097 /* [AS] Game list options */
\r
9103 static GLT_Item GLT_ItemInfo[] = {
\r
9104 { GLT_EVENT, "Event" },
\r
9105 { GLT_SITE, "Site" },
\r
9106 { GLT_DATE, "Date" },
\r
9107 { GLT_ROUND, "Round" },
\r
9108 { GLT_PLAYERS, "Players" },
\r
9109 { GLT_RESULT, "Result" },
\r
9110 { GLT_WHITE_ELO, "White Rating" },
\r
9111 { GLT_BLACK_ELO, "Black Rating" },
\r
9112 { GLT_TIME_CONTROL,"Time Control" },
\r
9113 { GLT_VARIANT, "Variant" },
\r
9114 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9118 const char * GLT_FindItem( char id )
\r
9120 const char * result = 0;
\r
9122 GLT_Item * list = GLT_ItemInfo;
\r
9124 while( list->id != 0 ) {
\r
9125 if( list->id == id ) {
\r
9126 result = list->name;
\r
9136 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9138 const char * name = GLT_FindItem( id );
\r
9141 if( index >= 0 ) {
\r
9142 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9145 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9150 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9154 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9157 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9161 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9163 pc = GLT_ALL_TAGS;
\r
9166 if( strchr( tags, *pc ) == 0 ) {
\r
9167 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9172 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9175 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9177 char result = '\0';
\r
9180 GLT_Item * list = GLT_ItemInfo;
\r
9182 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9183 while( list->id != 0 ) {
\r
9184 if( strcmp( list->name, name ) == 0 ) {
\r
9185 result = list->id;
\r
9196 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9198 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9199 int idx2 = idx1 + delta;
\r
9200 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9202 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9205 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9206 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9207 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9208 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9212 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9214 static char glt[64];
\r
9215 static char * lpUserGLT;
\r
9219 case WM_INITDIALOG:
\r
9220 lpUserGLT = (char *) lParam;
\r
9222 strcpy( glt, lpUserGLT );
\r
9224 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9226 /* Initialize list */
\r
9227 GLT_TagsToList( hDlg, glt );
\r
9229 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9234 switch( LOWORD(wParam) ) {
\r
9237 char * pc = lpUserGLT;
\r
9239 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9243 id = GLT_ListItemToTag( hDlg, idx );
\r
9247 } while( id != '\0' );
\r
9249 EndDialog( hDlg, 0 );
\r
9252 EndDialog( hDlg, 1 );
\r
9255 case IDC_GLT_Default:
\r
9256 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9257 GLT_TagsToList( hDlg, glt );
\r
9260 case IDC_GLT_Restore:
\r
9261 strcpy( glt, lpUserGLT );
\r
9262 GLT_TagsToList( hDlg, glt );
\r
9266 GLT_MoveSelection( hDlg, -1 );
\r
9269 case IDC_GLT_Down:
\r
9270 GLT_MoveSelection( hDlg, +1 );
\r
9280 int GameListOptions()
\r
9284 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9286 strcpy( glt, appData.gameListTags );
\r
9288 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9290 if( result == 0 ) {
\r
9291 /* [AS] Memory leak here! */
\r
9292 appData.gameListTags = strdup( glt );
\r
9300 DisplayIcsInteractionTitle(char *str)
\r
9302 char consoleTitle[MSG_SIZ];
\r
9304 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9305 SetWindowText(hwndConsole, consoleTitle);
\r
9309 DrawPosition(int fullRedraw, Board board)
\r
9311 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9318 fromX = fromY = -1;
\r
9319 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9320 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9321 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9322 dragInfo.lastpos = dragInfo.pos;
\r
9323 dragInfo.start.x = dragInfo.start.y = -1;
\r
9324 dragInfo.from = dragInfo.start;
\r
9326 DrawPosition(TRUE, NULL);
\r
9332 CommentPopUp(char *title, char *str)
\r
9334 HWND hwnd = GetActiveWindow();
\r
9335 EitherCommentPopUp(0, title, str, FALSE);
\r
9336 SetActiveWindow(hwnd);
\r
9340 CommentPopDown(void)
\r
9342 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9343 if (commentDialog) {
\r
9344 ShowWindow(commentDialog, SW_HIDE);
\r
9346 commentDialogUp = FALSE;
\r
9350 EditCommentPopUp(int index, char *title, char *str)
\r
9352 EitherCommentPopUp(index, title, str, TRUE);
\r
9359 MyPlaySound(&sounds[(int)SoundMove]);
\r
9362 VOID PlayIcsWinSound()
\r
9364 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9367 VOID PlayIcsLossSound()
\r
9369 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9372 VOID PlayIcsDrawSound()
\r
9374 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9377 VOID PlayIcsUnfinishedSound()
\r
9379 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9385 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9393 consoleEcho = TRUE;
\r
9394 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9395 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9396 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9405 consoleEcho = FALSE;
\r
9406 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9407 /* This works OK: set text and background both to the same color */
\r
9409 cf.crTextColor = COLOR_ECHOOFF;
\r
9410 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9411 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9414 /* No Raw()...? */
\r
9416 void Colorize(ColorClass cc, int continuation)
\r
9418 currentColorClass = cc;
\r
9419 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9420 consoleCF.crTextColor = textAttribs[cc].color;
\r
9421 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9422 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9428 static char buf[MSG_SIZ];
\r
9429 DWORD bufsiz = MSG_SIZ;
\r
9431 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9432 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9434 if (!GetUserName(buf, &bufsiz)) {
\r
9435 /*DisplayError("Error getting user name", GetLastError());*/
\r
9436 strcpy(buf, "User");
\r
9444 static char buf[MSG_SIZ];
\r
9445 DWORD bufsiz = MSG_SIZ;
\r
9447 if (!GetComputerName(buf, &bufsiz)) {
\r
9448 /*DisplayError("Error getting host name", GetLastError());*/
\r
9449 strcpy(buf, "Unknown");
\r
9456 ClockTimerRunning()
\r
9458 return clockTimerEvent != 0;
\r
9464 if (clockTimerEvent == 0) return FALSE;
\r
9465 KillTimer(hwndMain, clockTimerEvent);
\r
9466 clockTimerEvent = 0;
\r
9471 StartClockTimer(long millisec)
\r
9473 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9474 (UINT) millisec, NULL);
\r
9478 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9481 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9483 if(appData.noGUI) return;
\r
9484 hdc = GetDC(hwndMain);
\r
9485 if (!IsIconic(hwndMain)) {
\r
9486 DisplayAClock(hdc, timeRemaining, highlight,
\r
9487 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9489 if (highlight && iconCurrent == iconBlack) {
\r
9490 iconCurrent = iconWhite;
\r
9491 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9492 if (IsIconic(hwndMain)) {
\r
9493 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9496 (void) ReleaseDC(hwndMain, hdc);
\r
9498 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9502 DisplayBlackClock(long timeRemaining, int highlight)
\r
9505 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9507 if(appData.noGUI) return;
\r
9508 hdc = GetDC(hwndMain);
\r
9509 if (!IsIconic(hwndMain)) {
\r
9510 DisplayAClock(hdc, timeRemaining, highlight,
\r
9511 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9513 if (highlight && iconCurrent == iconWhite) {
\r
9514 iconCurrent = iconBlack;
\r
9515 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9516 if (IsIconic(hwndMain)) {
\r
9517 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9520 (void) ReleaseDC(hwndMain, hdc);
\r
9522 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9527 LoadGameTimerRunning()
\r
9529 return loadGameTimerEvent != 0;
\r
9533 StopLoadGameTimer()
\r
9535 if (loadGameTimerEvent == 0) return FALSE;
\r
9536 KillTimer(hwndMain, loadGameTimerEvent);
\r
9537 loadGameTimerEvent = 0;
\r
9542 StartLoadGameTimer(long millisec)
\r
9544 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9545 (UINT) millisec, NULL);
\r
9553 char fileTitle[MSG_SIZ];
\r
9555 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9556 f = OpenFileDialog(hwndMain, "a", defName,
\r
9557 appData.oldSaveStyle ? "gam" : "pgn",
\r
9559 "Save Game to File", NULL, fileTitle, NULL);
\r
9561 SaveGame(f, 0, "");
\r
9568 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9570 if (delayedTimerEvent != 0) {
\r
9571 if (appData.debugMode) {
\r
9572 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9574 KillTimer(hwndMain, delayedTimerEvent);
\r
9575 delayedTimerEvent = 0;
\r
9576 delayedTimerCallback();
\r
9578 delayedTimerCallback = cb;
\r
9579 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9580 (UINT) millisec, NULL);
\r
9583 DelayedEventCallback
\r
9586 if (delayedTimerEvent) {
\r
9587 return delayedTimerCallback;
\r
9594 CancelDelayedEvent()
\r
9596 if (delayedTimerEvent) {
\r
9597 KillTimer(hwndMain, delayedTimerEvent);
\r
9598 delayedTimerEvent = 0;
\r
9602 DWORD GetWin32Priority(int nice)
\r
9603 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9605 REALTIME_PRIORITY_CLASS 0x00000100
\r
9606 HIGH_PRIORITY_CLASS 0x00000080
\r
9607 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9608 NORMAL_PRIORITY_CLASS 0x00000020
\r
9609 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9610 IDLE_PRIORITY_CLASS 0x00000040
\r
9612 if (nice < -15) return 0x00000080;
\r
9613 if (nice < 0) return 0x00008000;
\r
9614 if (nice == 0) return 0x00000020;
\r
9615 if (nice < 15) return 0x00004000;
\r
9616 return 0x00000040;
\r
9619 /* Start a child process running the given program.
\r
9620 The process's standard output can be read from "from", and its
\r
9621 standard input can be written to "to".
\r
9622 Exit with fatal error if anything goes wrong.
\r
9623 Returns an opaque pointer that can be used to destroy the process
\r
9627 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9629 #define BUFSIZE 4096
\r
9631 HANDLE hChildStdinRd, hChildStdinWr,
\r
9632 hChildStdoutRd, hChildStdoutWr;
\r
9633 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9634 SECURITY_ATTRIBUTES saAttr;
\r
9636 PROCESS_INFORMATION piProcInfo;
\r
9637 STARTUPINFO siStartInfo;
\r
9639 char buf[MSG_SIZ];
\r
9642 if (appData.debugMode) {
\r
9643 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9648 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9649 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9650 saAttr.bInheritHandle = TRUE;
\r
9651 saAttr.lpSecurityDescriptor = NULL;
\r
9654 * The steps for redirecting child's STDOUT:
\r
9655 * 1. Create anonymous pipe to be STDOUT for child.
\r
9656 * 2. Create a noninheritable duplicate of read handle,
\r
9657 * and close the inheritable read handle.
\r
9660 /* Create a pipe for the child's STDOUT. */
\r
9661 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9662 return GetLastError();
\r
9665 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9666 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9667 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9668 FALSE, /* not inherited */
\r
9669 DUPLICATE_SAME_ACCESS);
\r
9671 return GetLastError();
\r
9673 CloseHandle(hChildStdoutRd);
\r
9676 * The steps for redirecting child's STDIN:
\r
9677 * 1. Create anonymous pipe to be STDIN for child.
\r
9678 * 2. Create a noninheritable duplicate of write handle,
\r
9679 * and close the inheritable write handle.
\r
9682 /* Create a pipe for the child's STDIN. */
\r
9683 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9684 return GetLastError();
\r
9687 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9688 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9689 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9690 FALSE, /* not inherited */
\r
9691 DUPLICATE_SAME_ACCESS);
\r
9693 return GetLastError();
\r
9695 CloseHandle(hChildStdinWr);
\r
9697 /* Arrange to (1) look in dir for the child .exe file, and
\r
9698 * (2) have dir be the child's working directory. Interpret
\r
9699 * dir relative to the directory WinBoard loaded from. */
\r
9700 GetCurrentDirectory(MSG_SIZ, buf);
\r
9701 SetCurrentDirectory(installDir);
\r
9702 SetCurrentDirectory(dir);
\r
9704 /* Now create the child process. */
\r
9706 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9707 siStartInfo.lpReserved = NULL;
\r
9708 siStartInfo.lpDesktop = NULL;
\r
9709 siStartInfo.lpTitle = NULL;
\r
9710 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9711 siStartInfo.cbReserved2 = 0;
\r
9712 siStartInfo.lpReserved2 = NULL;
\r
9713 siStartInfo.hStdInput = hChildStdinRd;
\r
9714 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9715 siStartInfo.hStdError = hChildStdoutWr;
\r
9717 fSuccess = CreateProcess(NULL,
\r
9718 cmdLine, /* command line */
\r
9719 NULL, /* process security attributes */
\r
9720 NULL, /* primary thread security attrs */
\r
9721 TRUE, /* handles are inherited */
\r
9722 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9723 NULL, /* use parent's environment */
\r
9725 &siStartInfo, /* STARTUPINFO pointer */
\r
9726 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9728 err = GetLastError();
\r
9729 SetCurrentDirectory(buf); /* return to prev directory */
\r
9734 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9735 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9736 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9739 /* Close the handles we don't need in the parent */
\r
9740 CloseHandle(piProcInfo.hThread);
\r
9741 CloseHandle(hChildStdinRd);
\r
9742 CloseHandle(hChildStdoutWr);
\r
9744 /* Prepare return value */
\r
9745 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9746 cp->kind = CPReal;
\r
9747 cp->hProcess = piProcInfo.hProcess;
\r
9748 cp->pid = piProcInfo.dwProcessId;
\r
9749 cp->hFrom = hChildStdoutRdDup;
\r
9750 cp->hTo = hChildStdinWrDup;
\r
9752 *pr = (void *) cp;
\r
9754 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9755 2000 where engines sometimes don't see the initial command(s)
\r
9756 from WinBoard and hang. I don't understand how that can happen,
\r
9757 but the Sleep is harmless, so I've put it in. Others have also
\r
9758 reported what may be the same problem, so hopefully this will fix
\r
9759 it for them too. */
\r
9767 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9769 ChildProc *cp; int result;
\r
9771 cp = (ChildProc *) pr;
\r
9772 if (cp == NULL) return;
\r
9774 switch (cp->kind) {
\r
9776 /* TerminateProcess is considered harmful, so... */
\r
9777 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9778 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9779 /* The following doesn't work because the chess program
\r
9780 doesn't "have the same console" as WinBoard. Maybe
\r
9781 we could arrange for this even though neither WinBoard
\r
9782 nor the chess program uses a console for stdio? */
\r
9783 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9785 /* [AS] Special termination modes for misbehaving programs... */
\r
9786 if( signal == 9 ) {
\r
9787 result = TerminateProcess( cp->hProcess, 0 );
\r
9789 if ( appData.debugMode) {
\r
9790 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9793 else if( signal == 10 ) {
\r
9794 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9796 if( dw != WAIT_OBJECT_0 ) {
\r
9797 result = TerminateProcess( cp->hProcess, 0 );
\r
9799 if ( appData.debugMode) {
\r
9800 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9806 CloseHandle(cp->hProcess);
\r
9810 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9814 closesocket(cp->sock);
\r
9819 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9820 closesocket(cp->sock);
\r
9821 closesocket(cp->sock2);
\r
9829 InterruptChildProcess(ProcRef pr)
\r
9833 cp = (ChildProc *) pr;
\r
9834 if (cp == NULL) return;
\r
9835 switch (cp->kind) {
\r
9837 /* The following doesn't work because the chess program
\r
9838 doesn't "have the same console" as WinBoard. Maybe
\r
9839 we could arrange for this even though neither WinBoard
\r
9840 nor the chess program uses a console for stdio */
\r
9841 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9846 /* Can't interrupt */
\r
9850 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9857 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9859 char cmdLine[MSG_SIZ];
\r
9861 if (port[0] == NULLCHAR) {
\r
9862 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9864 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9866 return StartChildProcess(cmdLine, "", pr);
\r
9870 /* Code to open TCP sockets */
\r
9873 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9878 struct sockaddr_in sa, mysa;
\r
9879 struct hostent FAR *hp;
\r
9880 unsigned short uport;
\r
9881 WORD wVersionRequested;
\r
9884 /* Initialize socket DLL */
\r
9885 wVersionRequested = MAKEWORD(1, 1);
\r
9886 err = WSAStartup(wVersionRequested, &wsaData);
\r
9887 if (err != 0) return err;
\r
9890 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9891 err = WSAGetLastError();
\r
9896 /* Bind local address using (mostly) don't-care values.
\r
9898 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9899 mysa.sin_family = AF_INET;
\r
9900 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9901 uport = (unsigned short) 0;
\r
9902 mysa.sin_port = htons(uport);
\r
9903 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9904 == SOCKET_ERROR) {
\r
9905 err = WSAGetLastError();
\r
9910 /* Resolve remote host name */
\r
9911 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9912 if (!(hp = gethostbyname(host))) {
\r
9913 unsigned int b0, b1, b2, b3;
\r
9915 err = WSAGetLastError();
\r
9917 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9918 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9919 hp->h_addrtype = AF_INET;
\r
9921 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9922 hp->h_addr_list[0] = (char *) malloc(4);
\r
9923 hp->h_addr_list[0][0] = (char) b0;
\r
9924 hp->h_addr_list[0][1] = (char) b1;
\r
9925 hp->h_addr_list[0][2] = (char) b2;
\r
9926 hp->h_addr_list[0][3] = (char) b3;
\r
9932 sa.sin_family = hp->h_addrtype;
\r
9933 uport = (unsigned short) atoi(port);
\r
9934 sa.sin_port = htons(uport);
\r
9935 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9937 /* Make connection */
\r
9938 if (connect(s, (struct sockaddr *) &sa,
\r
9939 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9940 err = WSAGetLastError();
\r
9945 /* Prepare return value */
\r
9946 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9947 cp->kind = CPSock;
\r
9949 *pr = (ProcRef *) cp;
\r
9955 OpenCommPort(char *name, ProcRef *pr)
\r
9960 char fullname[MSG_SIZ];
\r
9962 if (*name != '\\')
\r
9963 sprintf(fullname, "\\\\.\\%s", name);
\r
9965 strcpy(fullname, name);
\r
9967 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9968 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9969 if (h == (HANDLE) -1) {
\r
9970 return GetLastError();
\r
9974 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9976 /* Accumulate characters until a 100ms pause, then parse */
\r
9977 ct.ReadIntervalTimeout = 100;
\r
9978 ct.ReadTotalTimeoutMultiplier = 0;
\r
9979 ct.ReadTotalTimeoutConstant = 0;
\r
9980 ct.WriteTotalTimeoutMultiplier = 0;
\r
9981 ct.WriteTotalTimeoutConstant = 0;
\r
9982 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9984 /* Prepare return value */
\r
9985 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9986 cp->kind = CPComm;
\r
9989 *pr = (ProcRef *) cp;
\r
9995 OpenLoopback(ProcRef *pr)
\r
9997 DisplayFatalError("Not implemented", 0, 1);
\r
10003 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10007 SOCKET s, s2, s3;
\r
10008 struct sockaddr_in sa, mysa;
\r
10009 struct hostent FAR *hp;
\r
10010 unsigned short uport;
\r
10011 WORD wVersionRequested;
\r
10014 char stderrPortStr[MSG_SIZ];
\r
10016 /* Initialize socket DLL */
\r
10017 wVersionRequested = MAKEWORD(1, 1);
\r
10018 err = WSAStartup(wVersionRequested, &wsaData);
\r
10019 if (err != 0) return err;
\r
10021 /* Resolve remote host name */
\r
10022 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10023 if (!(hp = gethostbyname(host))) {
\r
10024 unsigned int b0, b1, b2, b3;
\r
10026 err = WSAGetLastError();
\r
10028 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10029 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10030 hp->h_addrtype = AF_INET;
\r
10031 hp->h_length = 4;
\r
10032 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10033 hp->h_addr_list[0] = (char *) malloc(4);
\r
10034 hp->h_addr_list[0][0] = (char) b0;
\r
10035 hp->h_addr_list[0][1] = (char) b1;
\r
10036 hp->h_addr_list[0][2] = (char) b2;
\r
10037 hp->h_addr_list[0][3] = (char) b3;
\r
10043 sa.sin_family = hp->h_addrtype;
\r
10044 uport = (unsigned short) 514;
\r
10045 sa.sin_port = htons(uport);
\r
10046 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10048 /* Bind local socket to unused "privileged" port address
\r
10050 s = INVALID_SOCKET;
\r
10051 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10052 mysa.sin_family = AF_INET;
\r
10053 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10054 for (fromPort = 1023;; fromPort--) {
\r
10055 if (fromPort < 0) {
\r
10057 return WSAEADDRINUSE;
\r
10059 if (s == INVALID_SOCKET) {
\r
10060 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10061 err = WSAGetLastError();
\r
10066 uport = (unsigned short) fromPort;
\r
10067 mysa.sin_port = htons(uport);
\r
10068 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10069 == SOCKET_ERROR) {
\r
10070 err = WSAGetLastError();
\r
10071 if (err == WSAEADDRINUSE) continue;
\r
10075 if (connect(s, (struct sockaddr *) &sa,
\r
10076 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10077 err = WSAGetLastError();
\r
10078 if (err == WSAEADDRINUSE) {
\r
10089 /* Bind stderr local socket to unused "privileged" port address
\r
10091 s2 = INVALID_SOCKET;
\r
10092 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10093 mysa.sin_family = AF_INET;
\r
10094 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10095 for (fromPort = 1023;; fromPort--) {
\r
10096 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10097 if (fromPort < 0) {
\r
10098 (void) closesocket(s);
\r
10100 return WSAEADDRINUSE;
\r
10102 if (s2 == INVALID_SOCKET) {
\r
10103 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10104 err = WSAGetLastError();
\r
10110 uport = (unsigned short) fromPort;
\r
10111 mysa.sin_port = htons(uport);
\r
10112 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10113 == SOCKET_ERROR) {
\r
10114 err = WSAGetLastError();
\r
10115 if (err == WSAEADDRINUSE) continue;
\r
10116 (void) closesocket(s);
\r
10120 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10121 err = WSAGetLastError();
\r
10122 if (err == WSAEADDRINUSE) {
\r
10124 s2 = INVALID_SOCKET;
\r
10127 (void) closesocket(s);
\r
10128 (void) closesocket(s2);
\r
10134 prevStderrPort = fromPort; // remember port used
\r
10135 sprintf(stderrPortStr, "%d", fromPort);
\r
10137 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10138 err = WSAGetLastError();
\r
10139 (void) closesocket(s);
\r
10140 (void) closesocket(s2);
\r
10145 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10146 err = WSAGetLastError();
\r
10147 (void) closesocket(s);
\r
10148 (void) closesocket(s2);
\r
10152 if (*user == NULLCHAR) user = UserName();
\r
10153 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10154 err = WSAGetLastError();
\r
10155 (void) closesocket(s);
\r
10156 (void) closesocket(s2);
\r
10160 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10161 err = WSAGetLastError();
\r
10162 (void) closesocket(s);
\r
10163 (void) closesocket(s2);
\r
10168 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10169 err = WSAGetLastError();
\r
10170 (void) closesocket(s);
\r
10171 (void) closesocket(s2);
\r
10175 (void) closesocket(s2); /* Stop listening */
\r
10177 /* Prepare return value */
\r
10178 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10179 cp->kind = CPRcmd;
\r
10182 *pr = (ProcRef *) cp;
\r
10189 AddInputSource(ProcRef pr, int lineByLine,
\r
10190 InputCallback func, VOIDSTAR closure)
\r
10192 InputSource *is, *is2 = NULL;
\r
10193 ChildProc *cp = (ChildProc *) pr;
\r
10195 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10196 is->lineByLine = lineByLine;
\r
10198 is->closure = closure;
\r
10199 is->second = NULL;
\r
10200 is->next = is->buf;
\r
10201 if (pr == NoProc) {
\r
10202 is->kind = CPReal;
\r
10203 consoleInputSource = is;
\r
10205 is->kind = cp->kind;
\r
10207 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10208 we create all threads suspended so that the is->hThread variable can be
\r
10209 safely assigned, then let the threads start with ResumeThread.
\r
10211 switch (cp->kind) {
\r
10213 is->hFile = cp->hFrom;
\r
10214 cp->hFrom = NULL; /* now owned by InputThread */
\r
10216 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10217 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10221 is->hFile = cp->hFrom;
\r
10222 cp->hFrom = NULL; /* now owned by InputThread */
\r
10224 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10225 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10229 is->sock = cp->sock;
\r
10231 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10232 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10236 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10238 is->sock = cp->sock;
\r
10239 is->second = is2;
\r
10240 is2->sock = cp->sock2;
\r
10241 is2->second = is2;
\r
10243 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10244 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10246 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10247 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10251 if( is->hThread != NULL ) {
\r
10252 ResumeThread( is->hThread );
\r
10255 if( is2 != NULL && is2->hThread != NULL ) {
\r
10256 ResumeThread( is2->hThread );
\r
10260 return (InputSourceRef) is;
\r
10264 RemoveInputSource(InputSourceRef isr)
\r
10268 is = (InputSource *) isr;
\r
10269 is->hThread = NULL; /* tell thread to stop */
\r
10270 CloseHandle(is->hThread);
\r
10271 if (is->second != NULL) {
\r
10272 is->second->hThread = NULL;
\r
10273 CloseHandle(is->second->hThread);
\r
10279 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10282 int outCount = SOCKET_ERROR;
\r
10283 ChildProc *cp = (ChildProc *) pr;
\r
10284 static OVERLAPPED ovl;
\r
10286 if (pr == NoProc) {
\r
10287 ConsoleOutput(message, count, FALSE);
\r
10291 if (ovl.hEvent == NULL) {
\r
10292 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10294 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10296 switch (cp->kind) {
\r
10299 outCount = send(cp->sock, message, count, 0);
\r
10300 if (outCount == SOCKET_ERROR) {
\r
10301 *outError = WSAGetLastError();
\r
10303 *outError = NO_ERROR;
\r
10308 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10309 &dOutCount, NULL)) {
\r
10310 *outError = NO_ERROR;
\r
10311 outCount = (int) dOutCount;
\r
10313 *outError = GetLastError();
\r
10318 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10319 &dOutCount, &ovl);
\r
10320 if (*outError == NO_ERROR) {
\r
10321 outCount = (int) dOutCount;
\r
10329 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10332 /* Ignore delay, not implemented for WinBoard */
\r
10333 return OutputToProcess(pr, message, count, outError);
\r
10338 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10339 char *buf, int count, int error)
\r
10341 DisplayFatalError("Not implemented", 0, 1);
\r
10344 /* see wgamelist.c for Game List functions */
\r
10345 /* see wedittags.c for Edit Tags functions */
\r
10352 char buf[MSG_SIZ];
\r
10355 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10356 f = fopen(buf, "r");
\r
10358 ProcessICSInitScript(f);
\r
10366 StartAnalysisClock()
\r
10368 if (analysisTimerEvent) return;
\r
10369 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10370 (UINT) 2000, NULL);
\r
10374 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10376 static HANDLE hwndText;
\r
10378 static int sizeX, sizeY;
\r
10379 int newSizeX, newSizeY, flags;
\r
10382 switch (message) {
\r
10383 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10384 /* Initialize the dialog items */
\r
10385 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10386 SetWindowText(hDlg, analysisTitle);
\r
10387 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10388 /* Size and position the dialog */
\r
10389 if (!analysisDialog) {
\r
10390 analysisDialog = hDlg;
\r
10391 flags = SWP_NOZORDER;
\r
10392 GetClientRect(hDlg, &rect);
\r
10393 sizeX = rect.right;
\r
10394 sizeY = rect.bottom;
\r
10395 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10396 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10397 WINDOWPLACEMENT wp;
\r
10398 EnsureOnScreen(&analysisX, &analysisY);
\r
10399 wp.length = sizeof(WINDOWPLACEMENT);
\r
10401 wp.showCmd = SW_SHOW;
\r
10402 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10403 wp.rcNormalPosition.left = analysisX;
\r
10404 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10405 wp.rcNormalPosition.top = analysisY;
\r
10406 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10407 SetWindowPlacement(hDlg, &wp);
\r
10409 GetClientRect(hDlg, &rect);
\r
10410 newSizeX = rect.right;
\r
10411 newSizeY = rect.bottom;
\r
10412 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10413 newSizeX, newSizeY);
\r
10414 sizeX = newSizeX;
\r
10415 sizeY = newSizeY;
\r
10420 case WM_COMMAND: /* message: received a command */
\r
10421 switch (LOWORD(wParam)) {
\r
10423 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10424 ExitAnalyzeMode();
\r
10436 newSizeX = LOWORD(lParam);
\r
10437 newSizeY = HIWORD(lParam);
\r
10438 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10439 sizeX = newSizeX;
\r
10440 sizeY = newSizeY;
\r
10443 case WM_GETMINMAXINFO:
\r
10444 /* Prevent resizing window too small */
\r
10445 mmi = (MINMAXINFO *) lParam;
\r
10446 mmi->ptMinTrackSize.x = 100;
\r
10447 mmi->ptMinTrackSize.y = 100;
\r
10454 AnalysisPopUp(char* title, char* str)
\r
10460 EngineOutputPopUp();
\r
10463 if (str == NULL) str = "";
\r
10464 p = (char *) malloc(2 * strlen(str) + 2);
\r
10467 if (*str == '\n') *q++ = '\r';
\r
10471 if (analysisText != NULL) free(analysisText);
\r
10472 analysisText = p;
\r
10474 if (analysisDialog) {
\r
10475 SetWindowText(analysisDialog, title);
\r
10476 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10477 ShowWindow(analysisDialog, SW_SHOW);
\r
10479 analysisTitle = title;
\r
10480 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10481 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10482 hwndMain, (DLGPROC)lpProc);
\r
10483 FreeProcInstance(lpProc);
\r
10485 analysisDialogUp = TRUE;
\r
10489 AnalysisPopDown()
\r
10491 if (analysisDialog) {
\r
10492 ShowWindow(analysisDialog, SW_HIDE);
\r
10494 analysisDialogUp = FALSE;
\r
10499 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10501 highlightInfo.sq[0].x = fromX;
\r
10502 highlightInfo.sq[0].y = fromY;
\r
10503 highlightInfo.sq[1].x = toX;
\r
10504 highlightInfo.sq[1].y = toY;
\r
10508 ClearHighlights()
\r
10510 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10511 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10515 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10517 premoveHighlightInfo.sq[0].x = fromX;
\r
10518 premoveHighlightInfo.sq[0].y = fromY;
\r
10519 premoveHighlightInfo.sq[1].x = toX;
\r
10520 premoveHighlightInfo.sq[1].y = toY;
\r
10524 ClearPremoveHighlights()
\r
10526 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10527 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10531 ShutDownFrontEnd()
\r
10533 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10534 DeleteClipboardTempFiles();
\r
10540 if (IsIconic(hwndMain))
\r
10541 ShowWindow(hwndMain, SW_RESTORE);
\r
10543 SetActiveWindow(hwndMain);
\r
10547 * Prototypes for animation support routines
\r
10549 static void ScreenSquare(int column, int row, POINT * pt);
\r
10550 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10551 POINT frames[], int * nFrames);
\r
10554 #define kFactor 4
\r
10557 AnimateMove(board, fromX, fromY, toX, toY)
\r
10564 ChessSquare piece;
\r
10565 POINT start, finish, mid;
\r
10566 POINT frames[kFactor * 2 + 1];
\r
10569 if (!appData.animate) return;
\r
10570 if (doingSizing) return;
\r
10571 if (fromY < 0 || fromX < 0) return;
\r
10572 piece = board[fromY][fromX];
\r
10573 if (piece >= EmptySquare) return;
\r
10575 ScreenSquare(fromX, fromY, &start);
\r
10576 ScreenSquare(toX, toY, &finish);
\r
10578 /* All pieces except knights move in straight line */
\r
10579 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10580 mid.x = start.x + (finish.x - start.x) / 2;
\r
10581 mid.y = start.y + (finish.y - start.y) / 2;
\r
10583 /* Knight: make diagonal movement then straight */
\r
10584 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10585 mid.x = start.x + (finish.x - start.x) / 2;
\r
10586 mid.y = finish.y;
\r
10588 mid.x = finish.x;
\r
10589 mid.y = start.y + (finish.y - start.y) / 2;
\r
10593 /* Don't use as many frames for very short moves */
\r
10594 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10595 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10597 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10599 animInfo.from.x = fromX;
\r
10600 animInfo.from.y = fromY;
\r
10601 animInfo.to.x = toX;
\r
10602 animInfo.to.y = toY;
\r
10603 animInfo.lastpos = start;
\r
10604 animInfo.piece = piece;
\r
10605 for (n = 0; n < nFrames; n++) {
\r
10606 animInfo.pos = frames[n];
\r
10607 DrawPosition(FALSE, NULL);
\r
10608 animInfo.lastpos = animInfo.pos;
\r
10609 Sleep(appData.animSpeed);
\r
10611 animInfo.pos = finish;
\r
10612 DrawPosition(FALSE, NULL);
\r
10613 animInfo.piece = EmptySquare;
\r
10616 /* Convert board position to corner of screen rect and color */
\r
10619 ScreenSquare(column, row, pt)
\r
10620 int column; int row; POINT * pt;
\r
10623 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10624 pt->y = lineGap + row * (squareSize + lineGap);
\r
10626 pt->x = lineGap + column * (squareSize + lineGap);
\r
10627 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10631 /* Generate a series of frame coords from start->mid->finish.
\r
10632 The movement rate doubles until the half way point is
\r
10633 reached, then halves back down to the final destination,
\r
10634 which gives a nice slow in/out effect. The algorithmn
\r
10635 may seem to generate too many intermediates for short
\r
10636 moves, but remember that the purpose is to attract the
\r
10637 viewers attention to the piece about to be moved and
\r
10638 then to where it ends up. Too few frames would be less
\r
10642 Tween(start, mid, finish, factor, frames, nFrames)
\r
10643 POINT * start; POINT * mid;
\r
10644 POINT * finish; int factor;
\r
10645 POINT frames[]; int * nFrames;
\r
10647 int n, fraction = 1, count = 0;
\r
10649 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10650 for (n = 0; n < factor; n++)
\r
10652 for (n = 0; n < factor; n++) {
\r
10653 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10654 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10656 fraction = fraction / 2;
\r
10660 frames[count] = *mid;
\r
10663 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10665 for (n = 0; n < factor; n++) {
\r
10666 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10667 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10669 fraction = fraction * 2;
\r
10671 *nFrames = count;
\r
10675 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10680 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10681 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10683 OutputDebugString( buf );
\r
10686 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10688 EvalGraphSet( first, last, current, pvInfoList );
\r
10691 void SetProgramStats( FrontEndProgramStats * stats )
\r
10696 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10697 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10699 OutputDebugString( buf );
\r
10702 EngineOutputUpdate( stats );
\r