2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
144 static int logoHeight = 0;
\r
145 static char messageText[MESSAGE_TEXT_MAX];
\r
146 static int clockTimerEvent = 0;
\r
147 static int loadGameTimerEvent = 0;
\r
148 static int analysisTimerEvent = 0;
\r
149 static DelayedEventCallback delayedTimerCallback;
\r
150 static int delayedTimerEvent = 0;
\r
151 static int buttonCount = 2;
\r
152 char *icsTextMenuString;
\r
154 char *firstChessProgramNames;
\r
155 char *secondChessProgramNames;
\r
157 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
159 #define PALETTESIZE 256
\r
161 HINSTANCE hInst; /* current instance */
\r
162 HWND hwndMain = NULL; /* root window*/
\r
163 HWND hwndConsole = NULL;
\r
164 BOOLEAN alwaysOnTop = FALSE;
\r
166 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
167 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
169 ColorClass currentColorClass;
\r
171 HWND hCommPort = NULL; /* currently open comm port */
\r
172 static HWND hwndPause; /* pause button */
\r
173 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
174 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
175 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
176 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
177 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
178 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
179 static HPEN gridPen = NULL;
\r
180 static HPEN highlightPen = NULL;
\r
181 static HPEN premovePen = NULL;
\r
182 static NPLOGPALETTE pLogPal;
\r
183 static BOOL paletteChanged = FALSE;
\r
184 static HICON iconWhite, iconBlack, iconCurrent;
\r
185 static int doingSizing = FALSE;
\r
186 static int lastSizing = 0;
\r
187 static int prevStderrPort;
\r
189 /* [AS] Support for background textures */
\r
190 #define BACK_TEXTURE_MODE_DISABLED 0
\r
191 #define BACK_TEXTURE_MODE_PLAIN 1
\r
192 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
194 static HBITMAP liteBackTexture = NULL;
\r
195 static HBITMAP darkBackTexture = NULL;
\r
196 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
198 static int backTextureSquareSize = 0;
\r
199 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
201 #if __GNUC__ && !defined(_winmajor)
\r
202 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
204 #define oldDialog (_winmajor < 4)
\r
207 char *defaultTextAttribs[] =
\r
209 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
210 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
220 int cliWidth, cliHeight;
\r
223 SizeInfo sizeInfo[] =
\r
225 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
226 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
227 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
228 { "petite", 33, 1, 1, 1, 0, 0 },
\r
229 { "slim", 37, 2, 1, 0, 0, 0 },
\r
230 { "small", 40, 2, 1, 0, 0, 0 },
\r
231 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
232 { "middling", 49, 2, 0, 0, 0, 0 },
\r
233 { "average", 54, 2, 0, 0, 0, 0 },
\r
234 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
235 { "medium", 64, 3, 0, 0, 0, 0 },
\r
236 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
237 { "large", 80, 3, 0, 0, 0, 0 },
\r
238 { "big", 87, 3, 0, 0, 0, 0 },
\r
239 { "huge", 95, 3, 0, 0, 0, 0 },
\r
240 { "giant", 108, 3, 0, 0, 0, 0 },
\r
241 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
242 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
243 { NULL, 0, 0, 0, 0, 0, 0 }
\r
246 #define MF(x) {x, {0, }, {0, }, 0}
\r
247 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
269 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
278 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
279 #define N_BUTTONS 5
\r
281 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
283 {"<<", IDM_ToStart, NULL, NULL},
\r
284 {"<", IDM_Backward, NULL, NULL},
\r
285 {"P", IDM_Pause, NULL, NULL},
\r
286 {">", IDM_Forward, NULL, NULL},
\r
287 {">>", IDM_ToEnd, NULL, NULL},
\r
290 int tinyLayout = 0, smallLayout = 0;
\r
291 #define MENU_BAR_ITEMS 6
\r
292 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
293 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
294 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
298 MySound sounds[(int)NSoundClasses];
\r
299 MyTextAttribs textAttribs[(int)NColorClasses];
\r
301 MyColorizeAttribs colorizeAttribs[] = {
\r
302 { (COLORREF)0, 0, "Shout Text" },
\r
303 { (COLORREF)0, 0, "SShout/CShout" },
\r
304 { (COLORREF)0, 0, "Channel 1 Text" },
\r
305 { (COLORREF)0, 0, "Channel Text" },
\r
306 { (COLORREF)0, 0, "Kibitz Text" },
\r
307 { (COLORREF)0, 0, "Tell Text" },
\r
308 { (COLORREF)0, 0, "Challenge Text" },
\r
309 { (COLORREF)0, 0, "Request Text" },
\r
310 { (COLORREF)0, 0, "Seek Text" },
\r
311 { (COLORREF)0, 0, "Normal Text" },
\r
312 { (COLORREF)0, 0, "None" }
\r
317 static char *commentTitle;
\r
318 static char *commentText;
\r
319 static int commentIndex;
\r
320 static Boolean editComment = FALSE;
\r
321 HWND commentDialog = NULL;
\r
322 BOOLEAN commentDialogUp = FALSE;
\r
323 static int commentX, commentY, commentH, commentW;
\r
325 static char *analysisTitle;
\r
326 static char *analysisText;
\r
327 HWND analysisDialog = NULL;
\r
328 BOOLEAN analysisDialogUp = FALSE;
\r
329 static int analysisX, analysisY, analysisH, analysisW;
\r
331 char errorTitle[MSG_SIZ];
\r
332 char errorMessage[2*MSG_SIZ];
\r
333 HWND errorDialog = NULL;
\r
334 BOOLEAN moveErrorMessageUp = FALSE;
\r
335 BOOLEAN consoleEcho = TRUE;
\r
336 CHARFORMAT consoleCF;
\r
337 COLORREF consoleBackgroundColor;
\r
339 char *programVersion;
\r
345 typedef int CPKind;
\r
354 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
357 #define INPUT_SOURCE_BUF_SIZE 4096
\r
359 typedef struct _InputSource {
\r
366 char buf[INPUT_SOURCE_BUF_SIZE];
\r
370 InputCallback func;
\r
371 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
375 InputSource *consoleInputSource;
\r
380 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
381 VOID ConsoleCreate();
\r
383 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
384 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
385 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
386 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
388 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
389 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
390 void ParseIcsTextMenu(char *icsTextMenuString);
\r
391 VOID PopUpMoveDialog(char firstchar);
\r
392 VOID PopUpNameDialog(char firstchar);
\r
393 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
397 int GameListOptions();
\r
399 HWND moveHistoryDialog = NULL;
\r
400 BOOLEAN moveHistoryDialogUp = FALSE;
\r
402 WindowPlacement wpMoveHistory;
\r
404 HWND evalGraphDialog = NULL;
\r
405 BOOLEAN evalGraphDialogUp = FALSE;
\r
407 WindowPlacement wpEvalGraph;
\r
409 HWND engineOutputDialog = NULL;
\r
410 BOOLEAN engineOutputDialogUp = FALSE;
\r
412 WindowPlacement wpEngineOutput;
\r
414 VOID MoveHistoryPopUp();
\r
415 VOID MoveHistoryPopDown();
\r
416 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
417 BOOL MoveHistoryIsUp();
\r
419 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
420 VOID EvalGraphPopUp();
\r
421 VOID EvalGraphPopDown();
\r
422 BOOL EvalGraphIsUp();
\r
424 VOID EngineOutputPopUp();
\r
425 VOID EngineOutputPopDown();
\r
426 BOOL EngineOutputIsUp();
\r
427 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
429 VOID GothicPopUp(char *title, VariantClass variant);
\r
431 * Setting "frozen" should disable all user input other than deleting
\r
432 * the window. We do this while engines are initializing themselves.
\r
434 static int frozen = 0;
\r
435 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
441 if (frozen) return;
\r
443 hmenu = GetMenu(hwndMain);
\r
444 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
445 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
447 DrawMenuBar(hwndMain);
\r
450 /* Undo a FreezeUI */
\r
456 if (!frozen) return;
\r
458 hmenu = GetMenu(hwndMain);
\r
459 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
460 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
462 DrawMenuBar(hwndMain);
\r
465 /*---------------------------------------------------------------------------*\
\r
469 \*---------------------------------------------------------------------------*/
\r
472 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
473 LPSTR lpCmdLine, int nCmdShow)
\r
476 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
480 LoadLibrary("RICHED32.DLL");
\r
481 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
483 if (!InitApplication(hInstance)) {
\r
486 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
490 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
491 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
492 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
494 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
496 while (GetMessage(&msg, /* message structure */
\r
497 NULL, /* handle of window receiving the message */
\r
498 0, /* lowest message to examine */
\r
499 0)) /* highest message to examine */
\r
501 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
502 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
503 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
504 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
505 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
506 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
507 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
508 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
509 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
510 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
511 TranslateMessage(&msg); /* Translates virtual key codes */
\r
512 DispatchMessage(&msg); /* Dispatches message to window */
\r
517 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
520 /*---------------------------------------------------------------------------*\
\r
522 * Initialization functions
\r
524 \*---------------------------------------------------------------------------*/
\r
527 InitApplication(HINSTANCE hInstance)
\r
531 /* Fill in window class structure with parameters that describe the */
\r
534 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
535 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
536 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
537 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
538 wc.hInstance = hInstance; /* Owner of this class */
\r
539 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
540 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
541 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
542 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
543 wc.lpszClassName = szAppName; /* Name to register as */
\r
545 /* Register the window class and return success/failure code. */
\r
546 if (!RegisterClass(&wc)) return FALSE;
\r
548 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
549 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
551 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
552 wc.hInstance = hInstance;
\r
553 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
554 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
555 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
556 wc.lpszMenuName = NULL;
\r
557 wc.lpszClassName = szConsoleName;
\r
559 if (!RegisterClass(&wc)) return FALSE;
\r
564 /* Set by InitInstance, used by EnsureOnScreen */
\r
565 int screenHeight, screenWidth;
\r
568 EnsureOnScreen(int *x, int *y)
\r
570 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
571 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
572 if (*x > screenWidth - 32) *x = 0;
\r
573 if (*y > screenHeight - 32) *y = 0;
\r
574 if (*x < 10) *x = 10;
\r
575 if (*y < gap) *y = gap;
\r
579 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
581 HWND hwnd; /* Main window handle. */
\r
583 WINDOWPLACEMENT wp;
\r
586 hInst = hInstance; /* Store instance handle in our global variable */
\r
588 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
589 *filepart = NULLCHAR;
\r
591 GetCurrentDirectory(MSG_SIZ, installDir);
\r
593 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
594 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
595 if (appData.debugMode) {
\r
596 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
597 setbuf(debugFP, NULL);
\r
602 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
603 // InitEngineUCI( installDir, &second );
\r
605 /* Create a main window for this application instance. */
\r
606 hwnd = CreateWindow(szAppName, szTitle,
\r
607 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
608 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
609 NULL, NULL, hInstance, NULL);
\r
612 /* If window could not be created, return "failure" */
\r
617 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
618 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
619 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
621 if (first.programLogo == NULL && appData.debugMode) {
\r
622 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
624 } else if(appData.autoLogo) {
\r
625 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
627 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
628 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
632 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
633 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
635 if (second.programLogo == NULL && appData.debugMode) {
\r
636 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
638 } else if(appData.autoLogo) {
\r
639 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
641 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
642 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
646 iconWhite = LoadIcon(hInstance, "icon_white");
\r
647 iconBlack = LoadIcon(hInstance, "icon_black");
\r
648 iconCurrent = iconWhite;
\r
649 InitDrawingColors();
\r
650 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
651 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
652 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
653 /* Compute window size for each board size, and use the largest
\r
654 size that fits on this screen as the default. */
\r
655 InitDrawingSizes((BoardSize)ibs, 0);
\r
656 if (boardSize == (BoardSize)-1 &&
\r
657 winHeight <= screenHeight
\r
658 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
659 && winWidth <= screenWidth) {
\r
660 boardSize = (BoardSize)ibs;
\r
664 InitDrawingSizes(boardSize, 0);
\r
666 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
668 /* [AS] Load textures if specified */
\r
669 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
671 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
672 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
673 liteBackTextureMode = appData.liteBackTextureMode;
\r
675 if (liteBackTexture == NULL && appData.debugMode) {
\r
676 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
680 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
681 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
682 darkBackTextureMode = appData.darkBackTextureMode;
\r
684 if (darkBackTexture == NULL && appData.debugMode) {
\r
685 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
689 mysrandom( (unsigned) time(NULL) );
\r
691 /* Make a console window if needed */
\r
692 if (appData.icsActive) {
\r
696 /* [AS] Restore layout */
\r
697 if( wpMoveHistory.visible ) {
\r
698 MoveHistoryPopUp();
\r
701 if( wpEvalGraph.visible ) {
\r
705 if( wpEngineOutput.visible ) {
\r
706 EngineOutputPopUp();
\r
711 /* Make the window visible; update its client area; and return "success" */
\r
712 EnsureOnScreen(&boardX, &boardY);
\r
713 wp.length = sizeof(WINDOWPLACEMENT);
\r
715 wp.showCmd = nCmdShow;
\r
716 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
717 wp.rcNormalPosition.left = boardX;
\r
718 wp.rcNormalPosition.right = boardX + winWidth;
\r
719 wp.rcNormalPosition.top = boardY;
\r
720 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
721 SetWindowPlacement(hwndMain, &wp);
\r
723 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
724 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
727 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
728 if( gameInfo.variant != VariantFischeRandom ) {
\r
729 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
734 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
735 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
737 ShowWindow(hwndConsole, nCmdShow);
\r
739 UpdateWindow(hwnd);
\r
747 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
748 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
749 ArgSettingsFilename
\r
757 String *pString; // ArgString
\r
758 int *pInt; // ArgInt
\r
759 float *pFloat; // ArgFloat
\r
760 Boolean *pBoolean; // ArgBoolean
\r
761 COLORREF *pColor; // ArgColor
\r
762 ColorClass cc; // ArgAttribs
\r
763 String *pFilename; // ArgFilename
\r
764 BoardSize *pBoardSize; // ArgBoardSize
\r
765 int whichFont; // ArgFont
\r
766 DCB *pDCB; // ArgCommSettings
\r
767 String *pFilename; // ArgSettingsFilename
\r
775 ArgDescriptor argDescriptors[] = {
\r
776 /* positional arguments */
\r
777 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
778 { "", ArgNone, NULL },
\r
779 /* keyword arguments */
\r
780 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
781 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
782 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
783 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
784 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
785 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
786 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
787 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
788 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
789 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
790 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
791 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
792 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
793 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
794 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
795 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
796 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
797 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
799 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
801 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
803 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
804 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
806 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
807 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
808 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
809 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
810 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
811 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
812 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
813 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
814 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
815 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
816 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
817 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
818 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
819 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
820 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
821 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
822 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
823 /*!!bitmapDirectory?*/
\r
824 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
825 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
826 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
827 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
828 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
829 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
830 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
831 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
832 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
833 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
834 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
835 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
836 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
837 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
838 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
839 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
840 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
841 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
842 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
843 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
844 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
845 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
846 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
847 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
848 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
849 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
850 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
851 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
852 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
853 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
854 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
855 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
856 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
857 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
858 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
859 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
860 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
861 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
862 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
863 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
864 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
865 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
866 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
867 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
868 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
869 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
870 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
871 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
872 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
873 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
874 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
875 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
876 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
877 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
878 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
879 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
880 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
881 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
882 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
883 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
884 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
885 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
886 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
887 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
888 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
889 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
890 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
891 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
892 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
893 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
894 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
895 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
896 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
897 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
898 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
899 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
900 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
901 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
902 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
903 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
904 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
905 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
906 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
907 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
908 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
909 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
910 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
911 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
912 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
913 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
914 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
915 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
916 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
917 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
918 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
919 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
920 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
921 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
922 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
923 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
924 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
925 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
926 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
927 TRUE }, /* must come after all fonts */
\r
928 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
929 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
930 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
931 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
932 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
933 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
934 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
935 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
936 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
937 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
938 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
939 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
940 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
941 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
942 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
943 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
944 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
945 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
946 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
947 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
948 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
949 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
950 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
951 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
952 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
953 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
954 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
955 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
956 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
957 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
958 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
960 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
961 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
963 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
964 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
965 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
966 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
967 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
968 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
969 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
970 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
971 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
972 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
973 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
974 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
975 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
976 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
977 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
978 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
979 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
980 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
981 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
982 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
983 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
984 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
985 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
986 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
987 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
988 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
989 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
990 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
991 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
992 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
993 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
994 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
995 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
996 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
997 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
998 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
999 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1000 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1001 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1002 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1003 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1004 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1005 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1006 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1007 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1008 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1009 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1010 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1011 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1012 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1013 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1014 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1015 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1016 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1017 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1018 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1019 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1020 { "highlightLastMove", ArgBoolean,
\r
1021 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1022 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1023 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1024 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1025 { "highlightDragging", ArgBoolean,
\r
1026 (LPVOID) &appData.highlightDragging, TRUE },
\r
1027 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1028 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1029 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1030 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1031 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1032 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1033 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1034 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1035 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1036 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1037 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1038 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1039 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1040 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1041 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1042 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1043 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1044 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1045 { "soundShout", ArgFilename,
\r
1046 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1047 { "soundSShout", ArgFilename,
\r
1048 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1049 { "soundChannel1", ArgFilename,
\r
1050 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1051 { "soundChannel", ArgFilename,
\r
1052 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1053 { "soundKibitz", ArgFilename,
\r
1054 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1055 { "soundTell", ArgFilename,
\r
1056 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1057 { "soundChallenge", ArgFilename,
\r
1058 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1059 { "soundRequest", ArgFilename,
\r
1060 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1061 { "soundSeek", ArgFilename,
\r
1062 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1063 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1064 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1065 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1066 { "soundIcsLoss", ArgFilename,
\r
1067 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1068 { "soundIcsDraw", ArgFilename,
\r
1069 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1070 { "soundIcsUnfinished", ArgFilename,
\r
1071 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1072 { "soundIcsAlarm", ArgFilename,
\r
1073 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1074 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1075 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1076 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1077 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1078 { "reuseChessPrograms", ArgBoolean,
\r
1079 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1080 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1081 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1082 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1083 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1084 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1085 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1086 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1087 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1088 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1089 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1090 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1091 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1092 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1093 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1094 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1095 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1096 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1097 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1098 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1099 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1100 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1101 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1102 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1103 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1104 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1105 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1106 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1107 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1108 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1109 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1110 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1111 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1112 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1113 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1114 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1115 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1116 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1118 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1120 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1121 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1122 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1123 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1124 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1125 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1126 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1127 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1128 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1129 /* [AS] New features */
\r
1130 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1131 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1132 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1133 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1134 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1135 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1136 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1137 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1138 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1139 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1140 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1141 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1142 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1143 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1144 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1145 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1146 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1147 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1148 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1149 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1150 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1151 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1152 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1153 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1154 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1155 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1156 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1157 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1158 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1159 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1160 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1161 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1162 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1163 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1164 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1165 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1166 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1167 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1168 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1169 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1170 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1171 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1172 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1173 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1174 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1175 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1176 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1177 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1179 /* [AS] Layout stuff */
\r
1180 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1181 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1182 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1183 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1184 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1186 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1187 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1188 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1189 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1190 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1192 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1193 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1194 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1195 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1196 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1198 /* [HGM] board-size, adjudication and misc. options */
\r
1199 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1200 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1201 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1202 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1203 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1204 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1205 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1206 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1207 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1208 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1209 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1210 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1211 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1212 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1213 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1214 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1215 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1216 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1217 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1218 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1219 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1220 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1221 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1222 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1223 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1224 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1225 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1228 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1229 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1230 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1231 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1232 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1233 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1234 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1235 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1236 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1237 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1238 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1239 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1240 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1242 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1243 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1244 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1245 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1246 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1247 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1248 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1250 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1251 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1252 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1253 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1254 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1255 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1256 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1257 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1258 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1259 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1260 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1261 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1262 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1263 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1264 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1265 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1266 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1267 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1269 /* [HGM] options for broadcasting and time odds */
\r
1270 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1271 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1272 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1273 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1274 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1275 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1276 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1277 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1278 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1279 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1280 { NULL, ArgNone, NULL, FALSE }
\r
1284 /* Kludge for indirection files on command line */
\r
1285 char* lastIndirectionFilename;
\r
1286 ArgDescriptor argDescriptorIndirection =
\r
1287 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1291 ExitArgError(char *msg, char *badArg)
\r
1293 char buf[MSG_SIZ];
\r
1295 sprintf(buf, "%s %s", msg, badArg);
\r
1296 DisplayFatalError(buf, 0, 2);
\r
1300 /* Command line font name parser. NULL name means do nothing.
\r
1301 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1302 For backward compatibility, syntax without the colon is also
\r
1303 accepted, but font names with digits in them won't work in that case.
\r
1306 ParseFontName(char *name, MyFontParams *mfp)
\r
1309 if (name == NULL) return;
\r
1311 q = strchr(p, ':');
\r
1313 if (q - p >= sizeof(mfp->faceName))
\r
1314 ExitArgError("Font name too long:", name);
\r
1315 memcpy(mfp->faceName, p, q - p);
\r
1316 mfp->faceName[q - p] = NULLCHAR;
\r
1319 q = mfp->faceName;
\r
1320 while (*p && !isdigit(*p)) {
\r
1322 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1323 ExitArgError("Font name too long:", name);
\r
1325 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1328 if (!*p) ExitArgError("Font point size missing:", name);
\r
1329 mfp->pointSize = (float) atof(p);
\r
1330 mfp->bold = (strchr(p, 'b') != NULL);
\r
1331 mfp->italic = (strchr(p, 'i') != NULL);
\r
1332 mfp->underline = (strchr(p, 'u') != NULL);
\r
1333 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1336 /* Color name parser.
\r
1337 X version accepts X color names, but this one
\r
1338 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1340 ParseColorName(char *name)
\r
1342 int red, green, blue, count;
\r
1343 char buf[MSG_SIZ];
\r
1345 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1347 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1348 &red, &green, &blue);
\r
1351 sprintf(buf, "Can't parse color name %s", name);
\r
1352 DisplayError(buf, 0);
\r
1353 return RGB(0, 0, 0);
\r
1355 return PALETTERGB(red, green, blue);
\r
1359 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1361 char *e = argValue;
\r
1365 if (*e == 'b') eff |= CFE_BOLD;
\r
1366 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1367 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1368 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1369 else if (*e == '#' || isdigit(*e)) break;
\r
1373 *color = ParseColorName(e);
\r
1378 ParseBoardSize(char *name)
\r
1380 BoardSize bs = SizeTiny;
\r
1381 while (sizeInfo[bs].name != NULL) {
\r
1382 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1385 ExitArgError("Unrecognized board size value", name);
\r
1386 return bs; /* not reached */
\r
1391 StringGet(void *getClosure)
\r
1393 char **p = (char **) getClosure;
\r
1398 FileGet(void *getClosure)
\r
1401 FILE* f = (FILE*) getClosure;
\r
1410 /* Parse settings file named "name". If file found, return the
\r
1411 full name in fullname and return TRUE; else return FALSE */
\r
1413 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1418 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1419 f = fopen(fullname, "r");
\r
1421 ParseArgs(FileGet, f);
\r
1430 ParseArgs(GetFunc get, void *cl)
\r
1432 char argName[ARG_MAX];
\r
1433 char argValue[ARG_MAX];
\r
1434 ArgDescriptor *ad;
\r
1443 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1444 if (ch == NULLCHAR) break;
\r
1446 /* Comment to end of line */
\r
1448 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1450 } else if (ch == '/' || ch == '-') {
\r
1453 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1454 ch != '\n' && ch != '\t') {
\r
1460 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1461 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1463 if (ad->argName == NULL)
\r
1464 ExitArgError("Unrecognized argument", argName);
\r
1466 } else if (ch == '@') {
\r
1467 /* Indirection file */
\r
1468 ad = &argDescriptorIndirection;
\r
1471 /* Positional argument */
\r
1472 ad = &argDescriptors[posarg++];
\r
1473 strcpy(argName, ad->argName);
\r
1476 if (ad->argType == ArgTrue) {
\r
1477 *(Boolean *) ad->argLoc = TRUE;
\r
1480 if (ad->argType == ArgFalse) {
\r
1481 *(Boolean *) ad->argLoc = FALSE;
\r
1485 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1486 if (ch == NULLCHAR || ch == '\n') {
\r
1487 ExitArgError("No value provided for argument", argName);
\r
1491 // Quoting with { }. No characters have to (or can) be escaped.
\r
1492 // Thus the string cannot contain a '}' character.
\r
1512 } else if (ch == '\'' || ch == '"') {
\r
1513 // Quoting with ' ' or " ", with \ as escape character.
\r
1514 // Inconvenient for long strings that may contain Windows filenames.
\r
1531 if (ch == start) {
\r
1540 if (ad->argType == ArgFilename
\r
1541 || ad->argType == ArgSettingsFilename) {
\r
1547 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1571 for (i = 0; i < 3; i++) {
\r
1572 if (ch >= '0' && ch <= '7') {
\r
1573 octval = octval*8 + (ch - '0');
\r
1580 *q++ = (char) octval;
\r
1591 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1598 switch (ad->argType) {
\r
1600 *(int *) ad->argLoc = atoi(argValue);
\r
1604 *(float *) ad->argLoc = (float) atof(argValue);
\r
1609 *(char **) ad->argLoc = strdup(argValue);
\r
1612 case ArgSettingsFilename:
\r
1614 char fullname[MSG_SIZ];
\r
1615 if (ParseSettingsFile(argValue, fullname)) {
\r
1616 if (ad->argLoc != NULL) {
\r
1617 *(char **) ad->argLoc = strdup(fullname);
\r
1620 if (ad->argLoc != NULL) {
\r
1622 ExitArgError("Failed to open indirection file", argValue);
\r
1629 switch (argValue[0]) {
\r
1632 *(Boolean *) ad->argLoc = TRUE;
\r
1636 *(Boolean *) ad->argLoc = FALSE;
\r
1639 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1645 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1648 case ArgAttribs: {
\r
1649 ColorClass cc = (ColorClass)ad->argLoc;
\r
1650 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1654 case ArgBoardSize:
\r
1655 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1659 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1662 case ArgCommSettings:
\r
1663 ParseCommSettings(argValue, &dcb);
\r
1667 ExitArgError("Unrecognized argument", argValue);
\r
1674 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1676 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1677 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1680 lf->lfEscapement = 0;
\r
1681 lf->lfOrientation = 0;
\r
1682 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1683 lf->lfItalic = mfp->italic;
\r
1684 lf->lfUnderline = mfp->underline;
\r
1685 lf->lfStrikeOut = mfp->strikeout;
\r
1686 lf->lfCharSet = DEFAULT_CHARSET;
\r
1687 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1688 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1689 lf->lfQuality = DEFAULT_QUALITY;
\r
1690 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1691 strcpy(lf->lfFaceName, mfp->faceName);
\r
1695 CreateFontInMF(MyFont *mf)
\r
1697 LFfromMFP(&mf->lf, &mf->mfp);
\r
1698 if (mf->hf) DeleteObject(mf->hf);
\r
1699 mf->hf = CreateFontIndirect(&mf->lf);
\r
1703 SetDefaultTextAttribs()
\r
1706 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1707 ParseAttribs(&textAttribs[cc].color,
\r
1708 &textAttribs[cc].effects,
\r
1709 defaultTextAttribs[cc]);
\r
1714 SetDefaultSounds()
\r
1718 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1719 textAttribs[cc].sound.name = strdup("");
\r
1720 textAttribs[cc].sound.data = NULL;
\r
1722 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1723 sounds[sc].name = strdup("");
\r
1724 sounds[sc].data = NULL;
\r
1726 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1734 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1735 MyLoadSound(&textAttribs[cc].sound);
\r
1737 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1738 MyLoadSound(&sounds[sc]);
\r
1743 InitAppData(LPSTR lpCmdLine)
\r
1746 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1749 programName = szAppName;
\r
1751 /* Initialize to defaults */
\r
1752 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1753 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1754 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1755 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1756 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1757 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1758 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1759 SetDefaultTextAttribs();
\r
1760 SetDefaultSounds();
\r
1761 appData.movesPerSession = MOVES_PER_SESSION;
\r
1762 appData.initString = INIT_STRING;
\r
1763 appData.secondInitString = INIT_STRING;
\r
1764 appData.firstComputerString = COMPUTER_STRING;
\r
1765 appData.secondComputerString = COMPUTER_STRING;
\r
1766 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1767 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1768 appData.firstPlaysBlack = FALSE;
\r
1769 appData.noChessProgram = FALSE;
\r
1770 chessProgram = FALSE;
\r
1771 appData.firstHost = FIRST_HOST;
\r
1772 appData.secondHost = SECOND_HOST;
\r
1773 appData.firstDirectory = FIRST_DIRECTORY;
\r
1774 appData.secondDirectory = SECOND_DIRECTORY;
\r
1775 appData.bitmapDirectory = "";
\r
1776 appData.remoteShell = REMOTE_SHELL;
\r
1777 appData.remoteUser = "";
\r
1778 appData.timeDelay = TIME_DELAY;
\r
1779 appData.timeControl = TIME_CONTROL;
\r
1780 appData.timeIncrement = TIME_INCREMENT;
\r
1781 appData.icsActive = FALSE;
\r
1782 appData.icsHost = "";
\r
1783 appData.icsPort = ICS_PORT;
\r
1784 appData.icsCommPort = ICS_COMM_PORT;
\r
1785 appData.icsLogon = ICS_LOGON;
\r
1786 appData.icsHelper = "";
\r
1787 appData.useTelnet = FALSE;
\r
1788 appData.telnetProgram = TELNET_PROGRAM;
\r
1789 appData.gateway = "";
\r
1790 appData.loadGameFile = "";
\r
1791 appData.loadGameIndex = 0;
\r
1792 appData.saveGameFile = "";
\r
1793 appData.autoSaveGames = FALSE;
\r
1794 appData.loadPositionFile = "";
\r
1795 appData.loadPositionIndex = 1;
\r
1796 appData.savePositionFile = "";
\r
1797 appData.matchMode = FALSE;
\r
1798 appData.matchGames = 0;
\r
1799 appData.monoMode = FALSE;
\r
1800 appData.debugMode = FALSE;
\r
1801 appData.clockMode = TRUE;
\r
1802 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1803 appData.Iconic = FALSE; /*unused*/
\r
1804 appData.searchTime = "";
\r
1805 appData.searchDepth = 0;
\r
1806 appData.showCoords = FALSE;
\r
1807 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1808 appData.autoCallFlag = FALSE;
\r
1809 appData.flipView = FALSE;
\r
1810 appData.autoFlipView = TRUE;
\r
1811 appData.cmailGameName = "";
\r
1812 appData.alwaysPromoteToQueen = FALSE;
\r
1813 appData.oldSaveStyle = FALSE;
\r
1814 appData.quietPlay = FALSE;
\r
1815 appData.showThinking = FALSE;
\r
1816 appData.ponderNextMove = TRUE;
\r
1817 appData.periodicUpdates = TRUE;
\r
1818 appData.popupExitMessage = TRUE;
\r
1819 appData.popupMoveErrors = FALSE;
\r
1820 appData.autoObserve = FALSE;
\r
1821 appData.autoComment = FALSE;
\r
1822 appData.animate = TRUE;
\r
1823 appData.animSpeed = 10;
\r
1824 appData.animateDragging = TRUE;
\r
1825 appData.highlightLastMove = TRUE;
\r
1826 appData.getMoveList = TRUE;
\r
1827 appData.testLegality = TRUE;
\r
1828 appData.premove = TRUE;
\r
1829 appData.premoveWhite = FALSE;
\r
1830 appData.premoveWhiteText = "";
\r
1831 appData.premoveBlack = FALSE;
\r
1832 appData.premoveBlackText = "";
\r
1833 appData.icsAlarm = TRUE;
\r
1834 appData.icsAlarmTime = 5000;
\r
1835 appData.autoRaiseBoard = TRUE;
\r
1836 appData.localLineEditing = TRUE;
\r
1837 appData.colorize = TRUE;
\r
1838 appData.reuseFirst = TRUE;
\r
1839 appData.reuseSecond = TRUE;
\r
1840 appData.blindfold = FALSE;
\r
1841 dcb.DCBlength = sizeof(DCB);
\r
1842 dcb.BaudRate = 9600;
\r
1843 dcb.fBinary = TRUE;
\r
1844 dcb.fParity = FALSE;
\r
1845 dcb.fOutxCtsFlow = FALSE;
\r
1846 dcb.fOutxDsrFlow = FALSE;
\r
1847 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1848 dcb.fDsrSensitivity = FALSE;
\r
1849 dcb.fTXContinueOnXoff = TRUE;
\r
1850 dcb.fOutX = FALSE;
\r
1852 dcb.fNull = FALSE;
\r
1853 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1854 dcb.fAbortOnError = FALSE;
\r
1855 dcb.wReserved = 0;
\r
1857 dcb.Parity = SPACEPARITY;
\r
1858 dcb.StopBits = ONESTOPBIT;
\r
1859 settingsFileName = SETTINGS_FILE;
\r
1860 saveSettingsOnExit = TRUE;
\r
1861 boardX = CW_USEDEFAULT;
\r
1862 boardY = CW_USEDEFAULT;
\r
1863 consoleX = CW_USEDEFAULT;
\r
1864 consoleY = CW_USEDEFAULT;
\r
1865 consoleW = CW_USEDEFAULT;
\r
1866 consoleH = CW_USEDEFAULT;
\r
1867 analysisX = CW_USEDEFAULT;
\r
1868 analysisY = CW_USEDEFAULT;
\r
1869 analysisW = CW_USEDEFAULT;
\r
1870 analysisH = CW_USEDEFAULT;
\r
1871 commentX = CW_USEDEFAULT;
\r
1872 commentY = CW_USEDEFAULT;
\r
1873 commentW = CW_USEDEFAULT;
\r
1874 commentH = CW_USEDEFAULT;
\r
1875 editTagsX = CW_USEDEFAULT;
\r
1876 editTagsY = CW_USEDEFAULT;
\r
1877 editTagsW = CW_USEDEFAULT;
\r
1878 editTagsH = CW_USEDEFAULT;
\r
1879 gameListX = CW_USEDEFAULT;
\r
1880 gameListY = CW_USEDEFAULT;
\r
1881 gameListW = CW_USEDEFAULT;
\r
1882 gameListH = CW_USEDEFAULT;
\r
1883 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1884 icsNames = ICS_NAMES;
\r
1885 firstChessProgramNames = FCP_NAMES;
\r
1886 secondChessProgramNames = SCP_NAMES;
\r
1887 appData.initialMode = "";
\r
1888 appData.variant = "normal";
\r
1889 appData.firstProtocolVersion = PROTOVER;
\r
1890 appData.secondProtocolVersion = PROTOVER;
\r
1891 appData.showButtonBar = TRUE;
\r
1893 /* [AS] New properties (see comments in header file) */
\r
1894 appData.firstScoreIsAbsolute = FALSE;
\r
1895 appData.secondScoreIsAbsolute = FALSE;
\r
1896 appData.saveExtendedInfoInPGN = FALSE;
\r
1897 appData.hideThinkingFromHuman = FALSE;
\r
1898 appData.liteBackTextureFile = "";
\r
1899 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1900 appData.darkBackTextureFile = "";
\r
1901 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1902 appData.renderPiecesWithFont = "";
\r
1903 appData.fontToPieceTable = "";
\r
1904 appData.fontBackColorWhite = 0;
\r
1905 appData.fontForeColorWhite = 0;
\r
1906 appData.fontBackColorBlack = 0;
\r
1907 appData.fontForeColorBlack = 0;
\r
1908 appData.fontPieceSize = 80;
\r
1909 appData.overrideLineGap = 1;
\r
1910 appData.adjudicateLossThreshold = 0;
\r
1911 appData.delayBeforeQuit = 0;
\r
1912 appData.delayAfterQuit = 0;
\r
1913 appData.nameOfDebugFile = "winboard.debug";
\r
1914 appData.pgnEventHeader = "Computer Chess Game";
\r
1915 appData.defaultFrcPosition = -1;
\r
1916 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1917 appData.saveOutOfBookInfo = TRUE;
\r
1918 appData.showEvalInMoveHistory = TRUE;
\r
1919 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1920 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1921 appData.highlightMoveWithArrow = FALSE;
\r
1922 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1923 appData.useStickyWindows = TRUE;
\r
1924 appData.adjudicateDrawMoves = 0;
\r
1925 appData.autoDisplayComment = TRUE;
\r
1926 appData.autoDisplayTags = TRUE;
\r
1927 appData.firstIsUCI = FALSE;
\r
1928 appData.secondIsUCI = FALSE;
\r
1929 appData.firstHasOwnBookUCI = TRUE;
\r
1930 appData.secondHasOwnBookUCI = TRUE;
\r
1931 appData.polyglotDir = "";
\r
1932 appData.usePolyglotBook = FALSE;
\r
1933 appData.polyglotBook = "";
\r
1934 appData.defaultHashSize = 64;
\r
1935 appData.defaultCacheSizeEGTB = 4;
\r
1936 appData.defaultPathEGTB = "c:\\egtb";
\r
1938 InitWindowPlacement( &wpMoveHistory );
\r
1939 InitWindowPlacement( &wpEvalGraph );
\r
1940 InitWindowPlacement( &wpEngineOutput );
\r
1942 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1943 appData.NrFiles = -1;
\r
1944 appData.NrRanks = -1;
\r
1945 appData.holdingsSize = -1;
\r
1946 appData.testClaims = FALSE;
\r
1947 appData.checkMates = FALSE;
\r
1948 appData.materialDraws= FALSE;
\r
1949 appData.trivialDraws = FALSE;
\r
1950 appData.ruleMoves = 51;
\r
1951 appData.drawRepeats = 6;
\r
1952 appData.matchPause = 10000;
\r
1953 appData.alphaRank = FALSE;
\r
1954 appData.allWhite = FALSE;
\r
1955 appData.upsideDown = FALSE;
\r
1956 appData.serverPause = 15;
\r
1957 appData.serverMovesName = NULL;
\r
1958 appData.suppressLoadMoves = FALSE;
\r
1959 appData.firstTimeOdds = 1;
\r
1960 appData.secondTimeOdds = 1;
\r
1961 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1962 appData.secondAccumulateTC = 1;
\r
1963 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1964 appData.secondNPS = -1;
\r
1965 appData.engineComments = 1;
\r
1966 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1967 appData.egtFormats = "";
\r
1970 appData.zippyTalk = ZIPPY_TALK;
\r
1971 appData.zippyPlay = ZIPPY_PLAY;
\r
1972 appData.zippyLines = ZIPPY_LINES;
\r
1973 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1974 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1975 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1976 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1977 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1978 appData.zippyUseI = ZIPPY_USE_I;
\r
1979 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1980 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1981 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1982 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1983 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1984 appData.zippyAbort = ZIPPY_ABORT;
\r
1985 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1986 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1987 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1990 /* Point font array elements to structures and
\r
1991 parse default font names */
\r
1992 for (i=0; i<NUM_FONTS; i++) {
\r
1993 for (j=0; j<NUM_SIZES; j++) {
\r
1994 font[j][i] = &fontRec[j][i];
\r
1995 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1999 /* Parse default settings file if any */
\r
2000 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2001 settingsFileName = strdup(buf);
\r
2004 /* Parse command line */
\r
2005 ParseArgs(StringGet, &lpCmdLine);
\r
2007 /* [HGM] make sure board size is acceptable */
\r
2008 if(appData.NrFiles > BOARD_SIZE ||
\r
2009 appData.NrRanks > BOARD_SIZE )
\r
2010 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2012 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2013 * with options from the command line, we now make an even higher priority
\r
2014 * overrule by WB options attached to the engine command line. This so that
\r
2015 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2018 if(appData.firstChessProgram != NULL) {
\r
2019 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2020 static char *f = "first";
\r
2021 char buf[MSG_SIZ], *q = buf;
\r
2022 if(p != NULL) { // engine command line contains WinBoard options
\r
2023 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2024 ParseArgs(StringGet, &q);
\r
2025 p[-1] = 0; // cut them offengine command line
\r
2028 // now do same for second chess program
\r
2029 if(appData.secondChessProgram != NULL) {
\r
2030 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2031 static char *s = "second";
\r
2032 char buf[MSG_SIZ], *q = buf;
\r
2033 if(p != NULL) { // engine command line contains WinBoard options
\r
2034 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2035 ParseArgs(StringGet, &q);
\r
2036 p[-1] = 0; // cut them offengine command line
\r
2041 /* Propagate options that affect others */
\r
2042 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2043 if (appData.icsActive || appData.noChessProgram) {
\r
2044 chessProgram = FALSE; /* not local chess program mode */
\r
2047 /* Open startup dialog if needed */
\r
2048 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2049 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2050 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2051 *appData.secondChessProgram == NULLCHAR))) {
\r
2054 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2055 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2056 FreeProcInstance(lpProc);
\r
2059 /* Make sure save files land in the right (?) directory */
\r
2060 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2061 appData.saveGameFile = strdup(buf);
\r
2063 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2064 appData.savePositionFile = strdup(buf);
\r
2067 /* Finish initialization for fonts and sounds */
\r
2068 for (i=0; i<NUM_FONTS; i++) {
\r
2069 for (j=0; j<NUM_SIZES; j++) {
\r
2070 CreateFontInMF(font[j][i]);
\r
2073 /* xboard, and older WinBoards, controlled the move sound with the
\r
2074 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2075 always turn the option on (so that the backend will call us),
\r
2076 then let the user turn the sound off by setting it to silence if
\r
2077 desired. To accommodate old winboard.ini files saved by old
\r
2078 versions of WinBoard, we also turn off the sound if the option
\r
2079 was initially set to false. */
\r
2080 if (!appData.ringBellAfterMoves) {
\r
2081 sounds[(int)SoundMove].name = strdup("");
\r
2082 appData.ringBellAfterMoves = TRUE;
\r
2084 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2085 SetCurrentDirectory(installDir);
\r
2087 SetCurrentDirectory(currDir);
\r
2089 p = icsTextMenuString;
\r
2090 if (p[0] == '@') {
\r
2091 FILE* f = fopen(p + 1, "r");
\r
2093 DisplayFatalError(p + 1, errno, 2);
\r
2096 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2098 buf[i] = NULLCHAR;
\r
2101 ParseIcsTextMenu(strdup(p));
\r
2108 HMENU hmenu = GetMenu(hwndMain);
\r
2110 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2111 MF_BYCOMMAND|((appData.icsActive &&
\r
2112 *appData.icsCommPort != NULLCHAR) ?
\r
2113 MF_ENABLED : MF_GRAYED));
\r
2114 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2115 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2116 MF_CHECKED : MF_UNCHECKED));
\r
2121 SaveSettings(char* name)
\r
2124 ArgDescriptor *ad;
\r
2125 WINDOWPLACEMENT wp;
\r
2126 char dir[MSG_SIZ];
\r
2128 if (!hwndMain) return;
\r
2130 GetCurrentDirectory(MSG_SIZ, dir);
\r
2131 SetCurrentDirectory(installDir);
\r
2132 f = fopen(name, "w");
\r
2133 SetCurrentDirectory(dir);
\r
2135 DisplayError(name, errno);
\r
2138 fprintf(f, ";\n");
\r
2139 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2140 fprintf(f, ";\n");
\r
2141 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2142 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2143 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2144 fprintf(f, ";\n");
\r
2146 wp.length = sizeof(WINDOWPLACEMENT);
\r
2147 GetWindowPlacement(hwndMain, &wp);
\r
2148 boardX = wp.rcNormalPosition.left;
\r
2149 boardY = wp.rcNormalPosition.top;
\r
2151 if (hwndConsole) {
\r
2152 GetWindowPlacement(hwndConsole, &wp);
\r
2153 consoleX = wp.rcNormalPosition.left;
\r
2154 consoleY = wp.rcNormalPosition.top;
\r
2155 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2156 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2159 if (analysisDialog) {
\r
2160 GetWindowPlacement(analysisDialog, &wp);
\r
2161 analysisX = wp.rcNormalPosition.left;
\r
2162 analysisY = wp.rcNormalPosition.top;
\r
2163 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2164 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2167 if (commentDialog) {
\r
2168 GetWindowPlacement(commentDialog, &wp);
\r
2169 commentX = wp.rcNormalPosition.left;
\r
2170 commentY = wp.rcNormalPosition.top;
\r
2171 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2172 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2175 if (editTagsDialog) {
\r
2176 GetWindowPlacement(editTagsDialog, &wp);
\r
2177 editTagsX = wp.rcNormalPosition.left;
\r
2178 editTagsY = wp.rcNormalPosition.top;
\r
2179 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2180 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2183 if (gameListDialog) {
\r
2184 GetWindowPlacement(gameListDialog, &wp);
\r
2185 gameListX = wp.rcNormalPosition.left;
\r
2186 gameListY = wp.rcNormalPosition.top;
\r
2187 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2188 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2191 /* [AS] Move history */
\r
2192 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2194 if( moveHistoryDialog ) {
\r
2195 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2196 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2197 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2198 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2199 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2202 /* [AS] Eval graph */
\r
2203 wpEvalGraph.visible = EvalGraphIsUp();
\r
2205 if( evalGraphDialog ) {
\r
2206 GetWindowPlacement(evalGraphDialog, &wp);
\r
2207 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2208 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2209 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2210 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2213 /* [AS] Engine output */
\r
2214 wpEngineOutput.visible = EngineOutputIsUp();
\r
2216 if( engineOutputDialog ) {
\r
2217 GetWindowPlacement(engineOutputDialog, &wp);
\r
2218 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2219 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2220 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2221 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2224 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2225 if (!ad->save) continue;
\r
2226 switch (ad->argType) {
\r
2229 char *p = *(char **)ad->argLoc;
\r
2230 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2231 /* Quote multiline values or \-containing values
\r
2232 with { } if possible */
\r
2233 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2235 /* Else quote with " " */
\r
2236 fprintf(f, "/%s=\"", ad->argName);
\r
2238 if (*p == '\n') fprintf(f, "\n");
\r
2239 else if (*p == '\r') fprintf(f, "\\r");
\r
2240 else if (*p == '\t') fprintf(f, "\\t");
\r
2241 else if (*p == '\b') fprintf(f, "\\b");
\r
2242 else if (*p == '\f') fprintf(f, "\\f");
\r
2243 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2244 else if (*p == '\"') fprintf(f, "\\\"");
\r
2245 else if (*p == '\\') fprintf(f, "\\\\");
\r
2249 fprintf(f, "\"\n");
\r
2254 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2257 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2260 fprintf(f, "/%s=%s\n", ad->argName,
\r
2261 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2264 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2267 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2271 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2272 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2273 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2278 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2279 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2280 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2281 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2282 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2283 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2284 (ta->effects) ? " " : "",
\r
2285 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2289 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2290 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2292 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2295 case ArgBoardSize:
\r
2296 fprintf(f, "/%s=%s\n", ad->argName,
\r
2297 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2302 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2303 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2304 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2305 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2306 ad->argName, mfp->faceName, mfp->pointSize,
\r
2307 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2308 mfp->bold ? "b" : "",
\r
2309 mfp->italic ? "i" : "",
\r
2310 mfp->underline ? "u" : "",
\r
2311 mfp->strikeout ? "s" : "");
\r
2315 case ArgCommSettings:
\r
2316 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2324 /*---------------------------------------------------------------------------*\
\r
2326 * GDI board drawing routines
\r
2328 \*---------------------------------------------------------------------------*/
\r
2330 /* [AS] Draw square using background texture */
\r
2331 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2336 return; /* Should never happen! */
\r
2339 SetGraphicsMode( dst, GM_ADVANCED );
\r
2346 /* X reflection */
\r
2351 x.eDx = (FLOAT) dw + dx - 1;
\r
2354 SetWorldTransform( dst, &x );
\r
2357 /* Y reflection */
\r
2363 x.eDy = (FLOAT) dh + dy - 1;
\r
2365 SetWorldTransform( dst, &x );
\r
2373 x.eDx = (FLOAT) dx;
\r
2374 x.eDy = (FLOAT) dy;
\r
2377 SetWorldTransform( dst, &x );
\r
2381 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2389 SetWorldTransform( dst, &x );
\r
2391 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2394 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2396 PM_WP = (int) WhitePawn,
\r
2397 PM_WN = (int) WhiteKnight,
\r
2398 PM_WB = (int) WhiteBishop,
\r
2399 PM_WR = (int) WhiteRook,
\r
2400 PM_WQ = (int) WhiteQueen,
\r
2401 PM_WF = (int) WhiteFerz,
\r
2402 PM_WW = (int) WhiteWazir,
\r
2403 PM_WE = (int) WhiteAlfil,
\r
2404 PM_WM = (int) WhiteMan,
\r
2405 PM_WO = (int) WhiteCannon,
\r
2406 PM_WU = (int) WhiteUnicorn,
\r
2407 PM_WH = (int) WhiteNightrider,
\r
2408 PM_WA = (int) WhiteAngel,
\r
2409 PM_WC = (int) WhiteMarshall,
\r
2410 PM_WAB = (int) WhiteCardinal,
\r
2411 PM_WD = (int) WhiteDragon,
\r
2412 PM_WL = (int) WhiteLance,
\r
2413 PM_WS = (int) WhiteCobra,
\r
2414 PM_WV = (int) WhiteFalcon,
\r
2415 PM_WSG = (int) WhiteSilver,
\r
2416 PM_WG = (int) WhiteGrasshopper,
\r
2417 PM_WK = (int) WhiteKing,
\r
2418 PM_BP = (int) BlackPawn,
\r
2419 PM_BN = (int) BlackKnight,
\r
2420 PM_BB = (int) BlackBishop,
\r
2421 PM_BR = (int) BlackRook,
\r
2422 PM_BQ = (int) BlackQueen,
\r
2423 PM_BF = (int) BlackFerz,
\r
2424 PM_BW = (int) BlackWazir,
\r
2425 PM_BE = (int) BlackAlfil,
\r
2426 PM_BM = (int) BlackMan,
\r
2427 PM_BO = (int) BlackCannon,
\r
2428 PM_BU = (int) BlackUnicorn,
\r
2429 PM_BH = (int) BlackNightrider,
\r
2430 PM_BA = (int) BlackAngel,
\r
2431 PM_BC = (int) BlackMarshall,
\r
2432 PM_BG = (int) BlackGrasshopper,
\r
2433 PM_BAB = (int) BlackCardinal,
\r
2434 PM_BD = (int) BlackDragon,
\r
2435 PM_BL = (int) BlackLance,
\r
2436 PM_BS = (int) BlackCobra,
\r
2437 PM_BV = (int) BlackFalcon,
\r
2438 PM_BSG = (int) BlackSilver,
\r
2439 PM_BK = (int) BlackKing
\r
2442 static HFONT hPieceFont = NULL;
\r
2443 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2444 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2445 static int fontBitmapSquareSize = 0;
\r
2446 static char pieceToFontChar[(int) EmptySquare] =
\r
2447 { 'p', 'n', 'b', 'r', 'q',
\r
2448 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2449 'k', 'o', 'm', 'v', 't', 'w',
\r
2450 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2453 extern BOOL SetCharTable( char *table, const char * map );
\r
2454 /* [HGM] moved to backend.c */
\r
2456 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2459 BYTE r1 = GetRValue( color );
\r
2460 BYTE g1 = GetGValue( color );
\r
2461 BYTE b1 = GetBValue( color );
\r
2467 /* Create a uniform background first */
\r
2468 hbrush = CreateSolidBrush( color );
\r
2469 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2470 FillRect( hdc, &rc, hbrush );
\r
2471 DeleteObject( hbrush );
\r
2474 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2475 int steps = squareSize / 2;
\r
2478 for( i=0; i<steps; i++ ) {
\r
2479 BYTE r = r1 - (r1-r2) * i / steps;
\r
2480 BYTE g = g1 - (g1-g2) * i / steps;
\r
2481 BYTE b = b1 - (b1-b2) * i / steps;
\r
2483 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2484 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2485 FillRect( hdc, &rc, hbrush );
\r
2486 DeleteObject(hbrush);
\r
2489 else if( mode == 2 ) {
\r
2490 /* Diagonal gradient, good more or less for every piece */
\r
2491 POINT triangle[3];
\r
2492 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2493 HBRUSH hbrush_old;
\r
2494 int steps = squareSize;
\r
2497 triangle[0].x = squareSize - steps;
\r
2498 triangle[0].y = squareSize;
\r
2499 triangle[1].x = squareSize;
\r
2500 triangle[1].y = squareSize;
\r
2501 triangle[2].x = squareSize;
\r
2502 triangle[2].y = squareSize - steps;
\r
2504 for( i=0; i<steps; i++ ) {
\r
2505 BYTE r = r1 - (r1-r2) * i / steps;
\r
2506 BYTE g = g1 - (g1-g2) * i / steps;
\r
2507 BYTE b = b1 - (b1-b2) * i / steps;
\r
2509 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2510 hbrush_old = SelectObject( hdc, hbrush );
\r
2511 Polygon( hdc, triangle, 3 );
\r
2512 SelectObject( hdc, hbrush_old );
\r
2513 DeleteObject(hbrush);
\r
2518 SelectObject( hdc, hpen );
\r
2523 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2524 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2525 piece: follow the steps as explained below.
\r
2527 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2531 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2535 int backColor = whitePieceColor;
\r
2536 int foreColor = blackPieceColor;
\r
2538 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2539 backColor = appData.fontBackColorWhite;
\r
2540 foreColor = appData.fontForeColorWhite;
\r
2542 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2543 backColor = appData.fontBackColorBlack;
\r
2544 foreColor = appData.fontForeColorBlack;
\r
2548 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2550 hbm_old = SelectObject( hdc, hbm );
\r
2554 rc.right = squareSize;
\r
2555 rc.bottom = squareSize;
\r
2557 /* Step 1: background is now black */
\r
2558 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2560 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2562 pt.x = (squareSize - sz.cx) / 2;
\r
2563 pt.y = (squareSize - sz.cy) / 2;
\r
2565 SetBkMode( hdc, TRANSPARENT );
\r
2566 SetTextColor( hdc, chroma );
\r
2567 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2568 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2570 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2571 /* Step 3: the area outside the piece is filled with white */
\r
2572 // FloodFill( hdc, 0, 0, chroma );
\r
2573 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2574 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2575 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2576 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2577 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2579 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2580 but if the start point is not inside the piece we're lost!
\r
2581 There should be a better way to do this... if we could create a region or path
\r
2582 from the fill operation we would be fine for example.
\r
2584 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2585 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2587 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2588 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2589 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2591 SelectObject( dc2, bm2 );
\r
2592 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2593 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2594 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2595 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2596 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2599 DeleteObject( bm2 );
\r
2602 SetTextColor( hdc, 0 );
\r
2604 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2605 draw the piece again in black for safety.
\r
2607 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2609 SelectObject( hdc, hbm_old );
\r
2611 if( hPieceMask[index] != NULL ) {
\r
2612 DeleteObject( hPieceMask[index] );
\r
2615 hPieceMask[index] = hbm;
\r
2618 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2620 SelectObject( hdc, hbm );
\r
2623 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2624 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2625 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2627 SelectObject( dc1, hPieceMask[index] );
\r
2628 SelectObject( dc2, bm2 );
\r
2629 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2630 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2633 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2634 the piece background and deletes (makes transparent) the rest.
\r
2635 Thanks to that mask, we are free to paint the background with the greates
\r
2636 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2637 We use this, to make gradients and give the pieces a "roundish" look.
\r
2639 SetPieceBackground( hdc, backColor, 2 );
\r
2640 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2644 DeleteObject( bm2 );
\r
2647 SetTextColor( hdc, foreColor );
\r
2648 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2650 SelectObject( hdc, hbm_old );
\r
2652 if( hPieceFace[index] != NULL ) {
\r
2653 DeleteObject( hPieceFace[index] );
\r
2656 hPieceFace[index] = hbm;
\r
2659 static int TranslatePieceToFontPiece( int piece )
\r
2689 case BlackMarshall:
\r
2693 case BlackNightrider:
\r
2699 case BlackUnicorn:
\r
2703 case BlackGrasshopper:
\r
2715 case BlackCardinal:
\r
2722 case WhiteMarshall:
\r
2726 case WhiteNightrider:
\r
2732 case WhiteUnicorn:
\r
2736 case WhiteGrasshopper:
\r
2748 case WhiteCardinal:
\r
2757 void CreatePiecesFromFont()
\r
2760 HDC hdc_window = NULL;
\r
2766 if( fontBitmapSquareSize < 0 ) {
\r
2767 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2771 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2772 fontBitmapSquareSize = -1;
\r
2776 if( fontBitmapSquareSize != squareSize ) {
\r
2777 hdc_window = GetDC( hwndMain );
\r
2778 hdc = CreateCompatibleDC( hdc_window );
\r
2780 if( hPieceFont != NULL ) {
\r
2781 DeleteObject( hPieceFont );
\r
2784 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2785 hPieceMask[i] = NULL;
\r
2786 hPieceFace[i] = NULL;
\r
2792 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2793 fontHeight = appData.fontPieceSize;
\r
2796 fontHeight = (fontHeight * squareSize) / 100;
\r
2798 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2800 lf.lfEscapement = 0;
\r
2801 lf.lfOrientation = 0;
\r
2802 lf.lfWeight = FW_NORMAL;
\r
2804 lf.lfUnderline = 0;
\r
2805 lf.lfStrikeOut = 0;
\r
2806 lf.lfCharSet = DEFAULT_CHARSET;
\r
2807 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2808 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2809 lf.lfQuality = PROOF_QUALITY;
\r
2810 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2811 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2812 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2814 hPieceFont = CreateFontIndirect( &lf );
\r
2816 if( hPieceFont == NULL ) {
\r
2817 fontBitmapSquareSize = -2;
\r
2820 /* Setup font-to-piece character table */
\r
2821 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2822 /* No (or wrong) global settings, try to detect the font */
\r
2823 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2825 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2827 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2828 /* DiagramTT* family */
\r
2829 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2831 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2832 /* Fairy symbols */
\r
2833 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2835 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2836 /* Good Companion (Some characters get warped as literal :-( */
\r
2837 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2838 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2839 SetCharTable(pieceToFontChar, s);
\r
2842 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2843 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2847 /* Create bitmaps */
\r
2848 hfont_old = SelectObject( hdc, hPieceFont );
\r
2850 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2851 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2852 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2853 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2854 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2855 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2856 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2857 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2858 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2859 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2860 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2861 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2863 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2864 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2865 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2866 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2867 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2868 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2869 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2870 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2875 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2896 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2897 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2900 SelectObject( hdc, hfont_old );
\r
2902 fontBitmapSquareSize = squareSize;
\r
2906 if( hdc != NULL ) {
\r
2910 if( hdc_window != NULL ) {
\r
2911 ReleaseDC( hwndMain, hdc_window );
\r
2916 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2920 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2921 if (gameInfo.event &&
\r
2922 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2923 strcmp(name, "k80s") == 0) {
\r
2924 strcpy(name, "tim");
\r
2926 return LoadBitmap(hinst, name);
\r
2930 /* Insert a color into the program's logical palette
\r
2931 structure. This code assumes the given color is
\r
2932 the result of the RGB or PALETTERGB macro, and it
\r
2933 knows how those macros work (which is documented).
\r
2936 InsertInPalette(COLORREF color)
\r
2938 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2940 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2941 DisplayFatalError("Too many colors", 0, 1);
\r
2942 pLogPal->palNumEntries--;
\r
2946 pe->peFlags = (char) 0;
\r
2947 pe->peRed = (char) (0xFF & color);
\r
2948 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2949 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2955 InitDrawingColors()
\r
2957 if (pLogPal == NULL) {
\r
2958 /* Allocate enough memory for a logical palette with
\r
2959 * PALETTESIZE entries and set the size and version fields
\r
2960 * of the logical palette structure.
\r
2962 pLogPal = (NPLOGPALETTE)
\r
2963 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2964 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2965 pLogPal->palVersion = 0x300;
\r
2967 pLogPal->palNumEntries = 0;
\r
2969 InsertInPalette(lightSquareColor);
\r
2970 InsertInPalette(darkSquareColor);
\r
2971 InsertInPalette(whitePieceColor);
\r
2972 InsertInPalette(blackPieceColor);
\r
2973 InsertInPalette(highlightSquareColor);
\r
2974 InsertInPalette(premoveHighlightColor);
\r
2976 /* create a logical color palette according the information
\r
2977 * in the LOGPALETTE structure.
\r
2979 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2981 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2982 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2983 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2984 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2985 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2986 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2988 /* [AS] Force rendering of the font-based pieces */
\r
2989 if( fontBitmapSquareSize > 0 ) {
\r
2990 fontBitmapSquareSize = 0;
\r
2996 BoardWidth(int boardSize, int n)
\r
2997 { /* [HGM] argument n added to allow different width and height */
\r
2998 int lineGap = sizeInfo[boardSize].lineGap;
\r
3000 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3001 lineGap = appData.overrideLineGap;
\r
3004 return (n + 1) * lineGap +
\r
3005 n * sizeInfo[boardSize].squareSize;
\r
3008 /* Respond to board resize by dragging edge */
\r
3010 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3012 BoardSize newSize = NUM_SIZES - 1;
\r
3013 static int recurse = 0;
\r
3014 if (IsIconic(hwndMain)) return;
\r
3015 if (recurse > 0) return;
\r
3017 while (newSize > 0) {
\r
3018 InitDrawingSizes(newSize, 0);
\r
3019 if(newSizeX >= sizeInfo[newSize].cliWidth ||
\r
3020 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3023 boardSize = newSize;
\r
3024 InitDrawingSizes(boardSize, flags);
\r
3031 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3033 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3034 ChessSquare piece;
\r
3035 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3037 SIZE clockSize, messageSize;
\r
3039 char buf[MSG_SIZ];
\r
3041 HMENU hmenu = GetMenu(hwndMain);
\r
3042 RECT crect, wrect;
\r
3044 LOGBRUSH logbrush;
\r
3046 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
3047 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3049 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3050 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3051 squareSize = sizeInfo[boardSize].squareSize;
\r
3052 lineGap = sizeInfo[boardSize].lineGap;
\r
3053 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3055 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3056 lineGap = appData.overrideLineGap;
\r
3059 if (tinyLayout != oldTinyLayout) {
\r
3060 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3062 style &= ~WS_SYSMENU;
\r
3063 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3064 "&Minimize\tCtrl+F4");
\r
3066 style |= WS_SYSMENU;
\r
3067 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3069 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3071 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3072 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3073 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3075 DrawMenuBar(hwndMain);
\r
3078 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3079 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3081 /* Get text area sizes */
\r
3082 hdc = GetDC(hwndMain);
\r
3083 if (appData.clockMode) {
\r
3084 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3086 sprintf(buf, "White");
\r
3088 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3089 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3090 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3091 str = "We only care about the height here";
\r
3092 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3093 SelectObject(hdc, oldFont);
\r
3094 ReleaseDC(hwndMain, hdc);
\r
3096 /* Compute where everything goes */
\r
3097 if(first.programLogo || second.programLogo) {
\r
3098 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3099 logoHeight = 2*clockSize.cy;
\r
3100 leftLogoRect.left = OUTER_MARGIN;
\r
3101 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3102 leftLogoRect.top = OUTER_MARGIN;
\r
3103 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3105 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3106 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3107 rightLogoRect.top = OUTER_MARGIN;
\r
3108 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3111 blackRect.left = leftLogoRect.right;
\r
3112 blackRect.right = rightLogoRect.left;
\r
3113 blackRect.top = OUTER_MARGIN;
\r
3114 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3116 whiteRect.left = blackRect.left ;
\r
3117 whiteRect.right = blackRect.right;
\r
3118 whiteRect.top = blackRect.bottom;
\r
3119 whiteRect.bottom = leftLogoRect.bottom;
\r
3121 whiteRect.left = OUTER_MARGIN;
\r
3122 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3123 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3124 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3126 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3127 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3128 blackRect.top = whiteRect.top;
\r
3129 blackRect.bottom = whiteRect.bottom;
\r
3132 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3133 if (appData.showButtonBar) {
\r
3134 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3135 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3137 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3139 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3140 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3142 boardRect.left = OUTER_MARGIN;
\r
3143 boardRect.right = boardRect.left + boardWidth;
\r
3144 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3145 boardRect.bottom = boardRect.top + boardHeight;
\r
3147 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3148 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3149 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3150 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3151 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3152 GetWindowRect(hwndMain, &wrect);
\r
3153 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3154 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3155 /* compensate if menu bar wrapped */
\r
3156 GetClientRect(hwndMain, &crect);
\r
3157 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3158 winHeight += offby;
\r
3160 case WMSZ_TOPLEFT:
\r
3161 SetWindowPos(hwndMain, NULL,
\r
3162 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3163 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3166 case WMSZ_TOPRIGHT:
\r
3168 SetWindowPos(hwndMain, NULL,
\r
3169 wrect.left, wrect.bottom - winHeight,
\r
3170 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3173 case WMSZ_BOTTOMLEFT:
\r
3175 SetWindowPos(hwndMain, NULL,
\r
3176 wrect.right - winWidth, wrect.top,
\r
3177 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3180 case WMSZ_BOTTOMRIGHT:
\r
3184 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3185 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3190 for (i = 0; i < N_BUTTONS; i++) {
\r
3191 if (buttonDesc[i].hwnd != NULL) {
\r
3192 DestroyWindow(buttonDesc[i].hwnd);
\r
3193 buttonDesc[i].hwnd = NULL;
\r
3195 if (appData.showButtonBar) {
\r
3196 buttonDesc[i].hwnd =
\r
3197 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3198 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3199 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3200 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3201 (HMENU) buttonDesc[i].id,
\r
3202 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3204 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3205 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3206 MAKELPARAM(FALSE, 0));
\r
3208 if (buttonDesc[i].id == IDM_Pause)
\r
3209 hwndPause = buttonDesc[i].hwnd;
\r
3210 buttonDesc[i].wndproc = (WNDPROC)
\r
3211 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3214 if (gridPen != NULL) DeleteObject(gridPen);
\r
3215 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3216 if (premovePen != NULL) DeleteObject(premovePen);
\r
3217 if (lineGap != 0) {
\r
3218 logbrush.lbStyle = BS_SOLID;
\r
3219 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3221 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3222 lineGap, &logbrush, 0, NULL);
\r
3223 logbrush.lbColor = highlightSquareColor;
\r
3225 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3226 lineGap, &logbrush, 0, NULL);
\r
3228 logbrush.lbColor = premoveHighlightColor;
\r
3230 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3231 lineGap, &logbrush, 0, NULL);
\r
3233 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3234 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3235 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3236 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3237 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3238 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3239 BOARD_WIDTH * (squareSize + lineGap);
\r
3240 lineGap / 2 + (i * (squareSize + lineGap));
\r
3241 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3243 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3244 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3245 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3246 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3247 lineGap / 2 + (i * (squareSize + lineGap));
\r
3248 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3249 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3250 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3254 /* [HGM] Licensing requirement */
\r
3256 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3259 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3261 GothicPopUp( "", VariantNormal);
\r
3264 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3265 oldBoardSize = boardSize;
\r
3266 oldTinyLayout = tinyLayout;
\r
3268 /* Load piece bitmaps for this board size */
\r
3269 for (i=0; i<=2; i++) {
\r
3270 for (piece = WhitePawn;
\r
3271 (int) piece < (int) BlackPawn;
\r
3272 piece = (ChessSquare) ((int) piece + 1)) {
\r
3273 if (pieceBitmap[i][piece] != NULL)
\r
3274 DeleteObject(pieceBitmap[i][piece]);
\r
3278 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3279 // Orthodox Chess pieces
\r
3280 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3281 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3282 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3283 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3284 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3285 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3286 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3287 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3288 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3289 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3290 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3291 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3292 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3293 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3294 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3295 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3296 // in Shogi, Hijack the unused Queen for Lance
\r
3297 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3298 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3299 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3301 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3302 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3303 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3306 if(squareSize <= 72 && squareSize >= 33) {
\r
3307 /* A & C are available in most sizes now */
\r
3308 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3309 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3310 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3311 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3312 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3313 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3314 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3315 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3316 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3317 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3318 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3319 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3320 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3321 } else { // Smirf-like
\r
3322 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3323 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3324 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3326 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3327 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3328 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3329 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3330 } else { // WinBoard standard
\r
3331 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3332 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3333 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3338 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3339 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3342 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3343 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3344 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3345 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3346 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3347 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3348 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3349 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3350 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3351 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3352 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3353 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3354 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3355 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3356 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3357 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3358 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3359 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3360 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3361 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3362 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3363 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3366 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3367 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3368 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3370 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3371 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3372 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3373 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3374 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3375 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3376 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3377 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3378 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3379 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3380 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3381 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3382 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3384 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3385 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3386 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3387 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3388 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3389 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3390 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3391 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3392 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3393 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3394 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3395 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3398 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3399 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3400 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3401 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3402 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3403 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3404 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3405 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3406 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3407 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3408 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3409 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3410 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3411 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3412 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3416 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3417 /* special Shogi support in this size */
\r
3418 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3419 for (piece = WhitePawn;
\r
3420 (int) piece < (int) BlackPawn;
\r
3421 piece = (ChessSquare) ((int) piece + 1)) {
\r
3422 if (pieceBitmap[i][piece] != NULL)
\r
3423 DeleteObject(pieceBitmap[i][piece]);
\r
3426 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3427 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3428 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3429 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3430 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3431 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3432 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3433 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3434 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3435 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3436 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3437 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3438 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3439 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3440 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3441 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3442 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3443 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3444 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3445 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3446 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3451 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3452 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3453 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3454 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3456 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3457 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3458 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3459 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3460 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3461 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3462 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3463 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3464 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3465 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3466 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3467 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3473 PieceBitmap(ChessSquare p, int kind)
\r
3475 if ((int) p >= (int) BlackPawn)
\r
3476 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3478 return pieceBitmap[kind][(int) p];
\r
3481 /***************************************************************/
\r
3483 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3484 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3486 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3487 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3491 SquareToPos(int row, int column, int * x, int * y)
\r
3494 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3495 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3497 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3498 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3503 DrawCoordsOnDC(HDC hdc)
\r
3505 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
3506 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
3507 char str[2] = { NULLCHAR, NULLCHAR };
\r
3508 int oldMode, oldAlign, x, y, start, i;
\r
3512 if (!appData.showCoords)
\r
3515 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3517 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3518 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3519 oldAlign = GetTextAlign(hdc);
\r
3520 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3522 y = boardRect.top + lineGap;
\r
3523 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3525 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3526 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3527 str[0] = files[start + i];
\r
3528 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3529 y += squareSize + lineGap;
\r
3532 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3534 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3535 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3536 str[0] = ranks[start + i];
\r
3537 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3538 x += squareSize + lineGap;
\r
3541 SelectObject(hdc, oldBrush);
\r
3542 SetBkMode(hdc, oldMode);
\r
3543 SetTextAlign(hdc, oldAlign);
\r
3544 SelectObject(hdc, oldFont);
\r
3548 DrawGridOnDC(HDC hdc)
\r
3552 if (lineGap != 0) {
\r
3553 oldPen = SelectObject(hdc, gridPen);
\r
3554 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3555 SelectObject(hdc, oldPen);
\r
3559 #define HIGHLIGHT_PEN 0
\r
3560 #define PREMOVE_PEN 1
\r
3563 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3566 HPEN oldPen, hPen;
\r
3567 if (lineGap == 0) return;
\r
3569 x1 = boardRect.left +
\r
3570 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3571 y1 = boardRect.top +
\r
3572 lineGap/2 + y * (squareSize + lineGap);
\r
3574 x1 = boardRect.left +
\r
3575 lineGap/2 + x * (squareSize + lineGap);
\r
3576 y1 = boardRect.top +
\r
3577 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3579 hPen = pen ? premovePen : highlightPen;
\r
3580 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3581 MoveToEx(hdc, x1, y1, NULL);
\r
3582 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3583 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3584 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3585 LineTo(hdc, x1, y1);
\r
3586 SelectObject(hdc, oldPen);
\r
3590 DrawHighlightsOnDC(HDC hdc)
\r
3593 for (i=0; i<2; i++) {
\r
3594 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3595 DrawHighlightOnDC(hdc, TRUE,
\r
3596 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3599 for (i=0; i<2; i++) {
\r
3600 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3601 premoveHighlightInfo.sq[i].y >= 0) {
\r
3602 DrawHighlightOnDC(hdc, TRUE,
\r
3603 premoveHighlightInfo.sq[i].x,
\r
3604 premoveHighlightInfo.sq[i].y,
\r
3610 /* Note: sqcolor is used only in monoMode */
\r
3611 /* Note that this code is largely duplicated in woptions.c,
\r
3612 function DrawSampleSquare, so that needs to be updated too */
\r
3614 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3616 HBITMAP oldBitmap;
\r
3620 if (appData.blindfold) return;
\r
3622 /* [AS] Use font-based pieces if needed */
\r
3623 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3624 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3625 CreatePiecesFromFont();
\r
3627 if( fontBitmapSquareSize == squareSize ) {
\r
3628 int index = TranslatePieceToFontPiece(piece);
\r
3630 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3634 squareSize, squareSize,
\r
3639 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3643 squareSize, squareSize,
\r
3652 if (appData.monoMode) {
\r
3653 SelectObject(tmphdc, PieceBitmap(piece,
\r
3654 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3655 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3656 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3658 tmpSize = squareSize;
\r
3660 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3661 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3662 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3663 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3664 x += (squareSize - minorSize)>>1;
\r
3665 y += squareSize - minorSize - 2;
\r
3666 tmpSize = minorSize;
\r
3668 if (color || appData.allWhite ) {
\r
3669 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3671 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3672 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3673 if(appData.upsideDown && color==flipView)
\r
3674 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3676 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3678 /* Use black piece color for outline of white pieces */
\r
3679 /* Not sure this looks really good (though xboard does it).
\r
3680 Maybe better to have another selectable color, default black */
\r
3681 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3682 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3683 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3685 /* Use black for outline of white pieces */
\r
3686 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3687 if(appData.upsideDown && color==flipView)
\r
3688 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3690 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3694 /* Use white piece color for details of black pieces */
\r
3695 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3696 WHITE_PIECE ones aren't always the right shape. */
\r
3697 /* Not sure this looks really good (though xboard does it).
\r
3698 Maybe better to have another selectable color, default medium gray? */
\r
3699 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3700 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3701 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3702 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3703 SelectObject(hdc, blackPieceBrush);
\r
3704 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3706 /* Use square color for details of black pieces */
\r
3707 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3708 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3709 if(appData.upsideDown && !flipView)
\r
3710 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3712 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3715 SelectObject(hdc, oldBrush);
\r
3716 SelectObject(tmphdc, oldBitmap);
\r
3720 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3721 int GetBackTextureMode( int algo )
\r
3723 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3727 case BACK_TEXTURE_MODE_PLAIN:
\r
3728 result = 1; /* Always use identity map */
\r
3730 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3731 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3739 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3740 to handle redraws cleanly (as random numbers would always be different).
\r
3742 VOID RebuildTextureSquareInfo()
\r
3752 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3754 if( liteBackTexture != NULL ) {
\r
3755 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3756 lite_w = bi.bmWidth;
\r
3757 lite_h = bi.bmHeight;
\r
3761 if( darkBackTexture != NULL ) {
\r
3762 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3763 dark_w = bi.bmWidth;
\r
3764 dark_h = bi.bmHeight;
\r
3768 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3769 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3770 if( (col + row) & 1 ) {
\r
3772 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3773 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3774 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3775 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3780 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3781 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3782 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3783 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3790 /* [AS] Arrow highlighting support */
\r
3792 static int A_WIDTH = 5; /* Width of arrow body */
\r
3794 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3795 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3797 static double Sqr( double x )
\r
3802 static int Round( double x )
\r
3804 return (int) (x + 0.5);
\r
3807 /* Draw an arrow between two points using current settings */
\r
3808 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3811 double dx, dy, j, k, x, y;
\r
3813 if( d_x == s_x ) {
\r
3814 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3816 arrow[0].x = s_x + A_WIDTH;
\r
3819 arrow[1].x = s_x + A_WIDTH;
\r
3820 arrow[1].y = d_y - h;
\r
3822 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3823 arrow[2].y = d_y - h;
\r
3828 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3829 arrow[4].y = d_y - h;
\r
3831 arrow[5].x = s_x - A_WIDTH;
\r
3832 arrow[5].y = d_y - h;
\r
3834 arrow[6].x = s_x - A_WIDTH;
\r
3837 else if( d_y == s_y ) {
\r
3838 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3841 arrow[0].y = s_y + A_WIDTH;
\r
3843 arrow[1].x = d_x - w;
\r
3844 arrow[1].y = s_y + A_WIDTH;
\r
3846 arrow[2].x = d_x - w;
\r
3847 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3852 arrow[4].x = d_x - w;
\r
3853 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3855 arrow[5].x = d_x - w;
\r
3856 arrow[5].y = s_y - A_WIDTH;
\r
3859 arrow[6].y = s_y - A_WIDTH;
\r
3862 /* [AS] Needed a lot of paper for this! :-) */
\r
3863 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3864 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3866 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3868 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3873 arrow[0].x = Round(x - j);
\r
3874 arrow[0].y = Round(y + j*dx);
\r
3876 arrow[1].x = Round(x + j);
\r
3877 arrow[1].y = Round(y - j*dx);
\r
3880 x = (double) d_x - k;
\r
3881 y = (double) d_y - k*dy;
\r
3884 x = (double) d_x + k;
\r
3885 y = (double) d_y + k*dy;
\r
3888 arrow[2].x = Round(x + j);
\r
3889 arrow[2].y = Round(y - j*dx);
\r
3891 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3892 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3897 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3898 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3900 arrow[6].x = Round(x - j);
\r
3901 arrow[6].y = Round(y + j*dx);
\r
3904 Polygon( hdc, arrow, 7 );
\r
3907 /* [AS] Draw an arrow between two squares */
\r
3908 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3910 int s_x, s_y, d_x, d_y;
\r
3917 if( s_col == d_col && s_row == d_row ) {
\r
3921 /* Get source and destination points */
\r
3922 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3923 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3926 d_y += squareSize / 4;
\r
3928 else if( d_y < s_y ) {
\r
3929 d_y += 3 * squareSize / 4;
\r
3932 d_y += squareSize / 2;
\r
3936 d_x += squareSize / 4;
\r
3938 else if( d_x < s_x ) {
\r
3939 d_x += 3 * squareSize / 4;
\r
3942 d_x += squareSize / 2;
\r
3945 s_x += squareSize / 2;
\r
3946 s_y += squareSize / 2;
\r
3948 /* Adjust width */
\r
3949 A_WIDTH = squareSize / 14;
\r
3952 stLB.lbStyle = BS_SOLID;
\r
3953 stLB.lbColor = appData.highlightArrowColor;
\r
3956 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3957 holdpen = SelectObject( hdc, hpen );
\r
3958 hbrush = CreateBrushIndirect( &stLB );
\r
3959 holdbrush = SelectObject( hdc, hbrush );
\r
3961 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3963 SelectObject( hdc, holdpen );
\r
3964 SelectObject( hdc, holdbrush );
\r
3965 DeleteObject( hpen );
\r
3966 DeleteObject( hbrush );
\r
3969 BOOL HasHighlightInfo()
\r
3971 BOOL result = FALSE;
\r
3973 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3974 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3982 BOOL IsDrawArrowEnabled()
\r
3984 BOOL result = FALSE;
\r
3986 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3993 VOID DrawArrowHighlight( HDC hdc )
\r
3995 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3996 DrawArrowBetweenSquares( hdc,
\r
3997 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3998 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4002 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4004 HRGN result = NULL;
\r
4006 if( HasHighlightInfo() ) {
\r
4007 int x1, y1, x2, y2;
\r
4008 int sx, sy, dx, dy;
\r
4010 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4011 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4013 sx = MIN( x1, x2 );
\r
4014 sy = MIN( y1, y2 );
\r
4015 dx = MAX( x1, x2 ) + squareSize;
\r
4016 dy = MAX( y1, y2 ) + squareSize;
\r
4018 result = CreateRectRgn( sx, sy, dx, dy );
\r
4025 Warning: this function modifies the behavior of several other functions.
\r
4027 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4028 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4029 repaint is scattered all over the place, which is not good for features such as
\r
4030 "arrow highlighting" that require a full repaint of the board.
\r
4032 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4033 user interaction, when speed is not so important) but especially to avoid errors
\r
4034 in the displayed graphics.
\r
4036 In such patched places, I always try refer to this function so there is a single
\r
4037 place to maintain knowledge.
\r
4039 To restore the original behavior, just return FALSE unconditionally.
\r
4041 BOOL IsFullRepaintPreferrable()
\r
4043 BOOL result = FALSE;
\r
4045 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4046 /* Arrow may appear on the board */
\r
4054 This function is called by DrawPosition to know whether a full repaint must
\r
4057 Only DrawPosition may directly call this function, which makes use of
\r
4058 some state information. Other function should call DrawPosition specifying
\r
4059 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4061 BOOL DrawPositionNeedsFullRepaint()
\r
4063 BOOL result = FALSE;
\r
4066 Probably a slightly better policy would be to trigger a full repaint
\r
4067 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4068 but animation is fast enough that it's difficult to notice.
\r
4070 if( animInfo.piece == EmptySquare ) {
\r
4071 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4080 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4082 int row, column, x, y, square_color, piece_color;
\r
4083 ChessSquare piece;
\r
4085 HDC texture_hdc = NULL;
\r
4087 /* [AS] Initialize background textures if needed */
\r
4088 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4089 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4090 if( backTextureSquareSize != squareSize
\r
4091 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4092 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4093 backTextureSquareSize = squareSize;
\r
4094 RebuildTextureSquareInfo();
\r
4097 texture_hdc = CreateCompatibleDC( hdc );
\r
4100 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4101 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4103 SquareToPos(row, column, &x, &y);
\r
4105 piece = board[row][column];
\r
4107 square_color = ((column + row) % 2) == 1;
\r
4108 if( gameInfo.variant == VariantXiangqi ) {
\r
4109 square_color = !InPalace(row, column);
\r
4110 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4111 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4113 piece_color = (int) piece < (int) BlackPawn;
\r
4116 /* [HGM] holdings file: light square or black */
\r
4117 if(column == BOARD_LEFT-2) {
\r
4118 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4121 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4125 if(column == BOARD_RGHT + 1 ) {
\r
4126 if( row < gameInfo.holdingsSize )
\r
4129 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4133 if(column == BOARD_LEFT-1 ) /* left align */
\r
4134 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4135 else if( column == BOARD_RGHT) /* right align */
\r
4136 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4138 if (appData.monoMode) {
\r
4139 if (piece == EmptySquare) {
\r
4140 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4141 square_color ? WHITENESS : BLACKNESS);
\r
4143 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4146 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4147 /* [AS] Draw the square using a texture bitmap */
\r
4148 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4149 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4150 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4153 squareSize, squareSize,
\r
4156 backTextureSquareInfo[r][c].mode,
\r
4157 backTextureSquareInfo[r][c].x,
\r
4158 backTextureSquareInfo[r][c].y );
\r
4160 SelectObject( texture_hdc, hbm );
\r
4162 if (piece != EmptySquare) {
\r
4163 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4167 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4169 oldBrush = SelectObject(hdc, brush );
\r
4170 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4171 SelectObject(hdc, oldBrush);
\r
4172 if (piece != EmptySquare)
\r
4173 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4178 if( texture_hdc != NULL ) {
\r
4179 DeleteDC( texture_hdc );
\r
4183 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4184 void fputDW(FILE *f, int x)
\r
4186 fputc(x & 255, f);
\r
4187 fputc(x>>8 & 255, f);
\r
4188 fputc(x>>16 & 255, f);
\r
4189 fputc(x>>24 & 255, f);
\r
4192 #define MAX_CLIPS 200 /* more than enough */
\r
4195 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4197 HBITMAP bufferBitmap;
\r
4202 int w = 100, h = 50;
\r
4204 if(cps->programLogo == NULL) return;
\r
4205 // GetClientRect(hwndMain, &Rect);
\r
4206 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4207 // Rect.bottom-Rect.top+1);
\r
4208 tmphdc = CreateCompatibleDC(hdc);
\r
4209 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4210 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4214 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4215 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4216 SelectObject(tmphdc, hbm);
\r
4221 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4223 static Board lastReq, lastDrawn;
\r
4224 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4225 static int lastDrawnFlipView = 0;
\r
4226 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4227 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4230 HBITMAP bufferBitmap;
\r
4231 HBITMAP oldBitmap;
\r
4233 HRGN clips[MAX_CLIPS];
\r
4234 ChessSquare dragged_piece = EmptySquare;
\r
4236 /* I'm undecided on this - this function figures out whether a full
\r
4237 * repaint is necessary on its own, so there's no real reason to have the
\r
4238 * caller tell it that. I think this can safely be set to FALSE - but
\r
4239 * if we trust the callers not to request full repaints unnessesarily, then
\r
4240 * we could skip some clipping work. In other words, only request a full
\r
4241 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4242 * gamestart and similar) --Hawk
\r
4244 Boolean fullrepaint = repaint;
\r
4246 if( DrawPositionNeedsFullRepaint() ) {
\r
4247 fullrepaint = TRUE;
\r
4251 if( fullrepaint ) {
\r
4252 static int repaint_count = 0;
\r
4256 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4257 OutputDebugString( buf );
\r
4261 if (board == NULL) {
\r
4262 if (!lastReqValid) {
\r
4267 CopyBoard(lastReq, board);
\r
4271 if (doingSizing) {
\r
4275 if (IsIconic(hwndMain)) {
\r
4279 if (hdc == NULL) {
\r
4280 hdc = GetDC(hwndMain);
\r
4281 if (!appData.monoMode) {
\r
4282 SelectPalette(hdc, hPal, FALSE);
\r
4283 RealizePalette(hdc);
\r
4287 releaseDC = FALSE;
\r
4291 fprintf(debugFP, "*******************************\n"
\r
4293 "dragInfo.from (%d,%d)\n"
\r
4294 "dragInfo.start (%d,%d)\n"
\r
4295 "dragInfo.pos (%d,%d)\n"
\r
4296 "dragInfo.lastpos (%d,%d)\n",
\r
4297 repaint ? "TRUE" : "FALSE",
\r
4298 dragInfo.from.x, dragInfo.from.y,
\r
4299 dragInfo.start.x, dragInfo.start.y,
\r
4300 dragInfo.pos.x, dragInfo.pos.y,
\r
4301 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4302 fprintf(debugFP, "prev: ");
\r
4303 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4304 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4305 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4308 fprintf(debugFP, "\n");
\r
4309 fprintf(debugFP, "board: ");
\r
4310 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4311 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4312 fprintf(debugFP, "%d ", board[row][column]);
\r
4315 fprintf(debugFP, "\n");
\r
4319 /* Create some work-DCs */
\r
4320 hdcmem = CreateCompatibleDC(hdc);
\r
4321 tmphdc = CreateCompatibleDC(hdc);
\r
4323 /* If dragging is in progress, we temporarely remove the piece */
\r
4324 /* [HGM] or temporarily decrease count if stacked */
\r
4325 /* !! Moved to before board compare !! */
\r
4326 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4327 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4328 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4329 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4330 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4332 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4333 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4334 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4336 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4339 /* Figure out which squares need updating by comparing the
\r
4340 * newest board with the last drawn board and checking if
\r
4341 * flipping has changed.
\r
4343 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4344 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4345 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4346 if (lastDrawn[row][column] != board[row][column]) {
\r
4347 SquareToPos(row, column, &x, &y);
\r
4348 clips[num_clips++] =
\r
4349 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4353 for (i=0; i<2; i++) {
\r
4354 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4355 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4356 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4357 lastDrawnHighlight.sq[i].y >= 0) {
\r
4358 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4359 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4360 clips[num_clips++] =
\r
4361 CreateRectRgn(x - lineGap, y - lineGap,
\r
4362 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4364 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4365 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4366 clips[num_clips++] =
\r
4367 CreateRectRgn(x - lineGap, y - lineGap,
\r
4368 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4372 for (i=0; i<2; i++) {
\r
4373 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4374 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4375 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4376 lastDrawnPremove.sq[i].y >= 0) {
\r
4377 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4378 lastDrawnPremove.sq[i].x, &x, &y);
\r
4379 clips[num_clips++] =
\r
4380 CreateRectRgn(x - lineGap, y - lineGap,
\r
4381 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4383 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4384 premoveHighlightInfo.sq[i].y >= 0) {
\r
4385 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4386 premoveHighlightInfo.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
4394 fullrepaint = TRUE;
\r
4397 /* Create a buffer bitmap - this is the actual bitmap
\r
4398 * being written to. When all the work is done, we can
\r
4399 * copy it to the real DC (the screen). This avoids
\r
4400 * the problems with flickering.
\r
4402 GetClientRect(hwndMain, &Rect);
\r
4403 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4404 Rect.bottom-Rect.top+1);
\r
4405 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4406 if (!appData.monoMode) {
\r
4407 SelectPalette(hdcmem, hPal, FALSE);
\r
4410 /* Create clips for dragging */
\r
4411 if (!fullrepaint) {
\r
4412 if (dragInfo.from.x >= 0) {
\r
4413 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4414 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4416 if (dragInfo.start.x >= 0) {
\r
4417 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4418 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4420 if (dragInfo.pos.x >= 0) {
\r
4421 x = dragInfo.pos.x - squareSize / 2;
\r
4422 y = dragInfo.pos.y - squareSize / 2;
\r
4423 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4425 if (dragInfo.lastpos.x >= 0) {
\r
4426 x = dragInfo.lastpos.x - squareSize / 2;
\r
4427 y = dragInfo.lastpos.y - squareSize / 2;
\r
4428 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4432 /* Are we animating a move?
\r
4434 * - remove the piece from the board (temporarely)
\r
4435 * - calculate the clipping region
\r
4437 if (!fullrepaint) {
\r
4438 if (animInfo.piece != EmptySquare) {
\r
4439 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4440 x = boardRect.left + animInfo.lastpos.x;
\r
4441 y = boardRect.top + animInfo.lastpos.y;
\r
4442 x2 = boardRect.left + animInfo.pos.x;
\r
4443 y2 = boardRect.top + animInfo.pos.y;
\r
4444 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4445 /* Slight kludge. The real problem is that after AnimateMove is
\r
4446 done, the position on the screen does not match lastDrawn.
\r
4447 This currently causes trouble only on e.p. captures in
\r
4448 atomic, where the piece moves to an empty square and then
\r
4449 explodes. The old and new positions both had an empty square
\r
4450 at the destination, but animation has drawn a piece there and
\r
4451 we have to remember to erase it. */
\r
4452 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4456 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4457 if (num_clips == 0)
\r
4458 fullrepaint = TRUE;
\r
4460 /* Set clipping on the memory DC */
\r
4461 if (!fullrepaint) {
\r
4462 SelectClipRgn(hdcmem, clips[0]);
\r
4463 for (x = 1; x < num_clips; x++) {
\r
4464 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4465 abort(); // this should never ever happen!
\r
4469 /* Do all the drawing to the memory DC */
\r
4470 DrawGridOnDC(hdcmem);
\r
4471 DrawHighlightsOnDC(hdcmem);
\r
4472 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4475 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4476 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4479 if( appData.highlightMoveWithArrow ) {
\r
4480 DrawArrowHighlight(hdcmem);
\r
4483 DrawCoordsOnDC(hdcmem);
\r
4485 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4486 /* to make sure lastDrawn contains what is actually drawn */
\r
4488 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4489 if (dragged_piece != EmptySquare) {
\r
4490 /* [HGM] or restack */
\r
4491 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4492 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4494 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4495 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4496 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4497 x = dragInfo.pos.x - squareSize / 2;
\r
4498 y = dragInfo.pos.y - squareSize / 2;
\r
4499 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4500 ((int) dragged_piece < (int) BlackPawn),
\r
4501 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4504 /* Put the animated piece back into place and draw it */
\r
4505 if (animInfo.piece != EmptySquare) {
\r
4506 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4507 x = boardRect.left + animInfo.pos.x;
\r
4508 y = boardRect.top + animInfo.pos.y;
\r
4509 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4510 ((int) animInfo.piece < (int) BlackPawn),
\r
4511 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4514 /* Release the bufferBitmap by selecting in the old bitmap
\r
4515 * and delete the memory DC
\r
4517 SelectObject(hdcmem, oldBitmap);
\r
4520 /* Set clipping on the target DC */
\r
4521 if (!fullrepaint) {
\r
4522 SelectClipRgn(hdc, clips[0]);
\r
4523 for (x = 1; x < num_clips; x++) {
\r
4524 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4525 abort(); // this should never ever happen!
\r
4529 /* Copy the new bitmap onto the screen in one go.
\r
4530 * This way we avoid any flickering
\r
4532 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4533 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4534 boardRect.right - boardRect.left,
\r
4535 boardRect.bottom - boardRect.top,
\r
4536 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4537 if(saveDiagFlag) {
\r
4538 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4539 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4541 GetObject(bufferBitmap, sizeof(b), &b);
\r
4542 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4543 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4544 bih.biWidth = b.bmWidth;
\r
4545 bih.biHeight = b.bmHeight;
\r
4547 bih.biBitCount = b.bmBitsPixel;
\r
4548 bih.biCompression = 0;
\r
4549 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4550 bih.biXPelsPerMeter = 0;
\r
4551 bih.biYPelsPerMeter = 0;
\r
4552 bih.biClrUsed = 0;
\r
4553 bih.biClrImportant = 0;
\r
4554 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4555 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4556 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4557 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4560 wb = b.bmWidthBytes;
\r
4562 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4563 int k = ((int*) pData)[i];
\r
4564 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4565 if(j >= 16) break;
\r
4567 if(j >= nrColors) nrColors = j+1;
\r
4569 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4571 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4572 for(w=0; w<(wb>>2); w+=2) {
\r
4573 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4574 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4575 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4576 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4577 pData[p++] = m | j<<4;
\r
4579 while(p&3) pData[p++] = 0;
\r
4582 wb = (wb+31>>5)<<2;
\r
4584 // write BITMAPFILEHEADER
\r
4585 fprintf(diagFile, "BM");
\r
4586 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4587 fputDW(diagFile, 0);
\r
4588 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4589 // write BITMAPINFOHEADER
\r
4590 fputDW(diagFile, 40);
\r
4591 fputDW(diagFile, b.bmWidth);
\r
4592 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4593 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4594 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4595 fputDW(diagFile, 0);
\r
4596 fputDW(diagFile, 0);
\r
4597 fputDW(diagFile, 0);
\r
4598 fputDW(diagFile, 0);
\r
4599 fputDW(diagFile, 0);
\r
4600 fputDW(diagFile, 0);
\r
4601 // write color table
\r
4603 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4604 // write bitmap data
\r
4605 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4606 fputc(pData[i], diagFile);
\r
4611 SelectObject(tmphdc, oldBitmap);
\r
4613 /* Massive cleanup */
\r
4614 for (x = 0; x < num_clips; x++)
\r
4615 DeleteObject(clips[x]);
\r
4618 DeleteObject(bufferBitmap);
\r
4621 ReleaseDC(hwndMain, hdc);
\r
4623 if (lastDrawnFlipView != flipView) {
\r
4625 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4627 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4630 /* CopyBoard(lastDrawn, board);*/
\r
4631 lastDrawnHighlight = highlightInfo;
\r
4632 lastDrawnPremove = premoveHighlightInfo;
\r
4633 lastDrawnFlipView = flipView;
\r
4634 lastDrawnValid = 1;
\r
4637 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4645 saveDiagFlag = 1; diagFile = f;
\r
4646 HDCDrawPosition(NULL, TRUE, NULL);
\r
4650 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4657 /*---------------------------------------------------------------------------*\
\r
4658 | CLIENT PAINT PROCEDURE
\r
4659 | This is the main event-handler for the WM_PAINT message.
\r
4661 \*---------------------------------------------------------------------------*/
\r
4663 PaintProc(HWND hwnd)
\r
4669 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4670 if (IsIconic(hwnd)) {
\r
4671 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4673 if (!appData.monoMode) {
\r
4674 SelectPalette(hdc, hPal, FALSE);
\r
4675 RealizePalette(hdc);
\r
4677 HDCDrawPosition(hdc, 1, NULL);
\r
4679 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4680 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4681 ETO_CLIPPED|ETO_OPAQUE,
\r
4682 &messageRect, messageText, strlen(messageText), NULL);
\r
4683 SelectObject(hdc, oldFont);
\r
4684 DisplayBothClocks();
\r
4686 EndPaint(hwnd,&ps);
\r
4694 * If the user selects on a border boundary, return -1; if off the board,
\r
4695 * return -2. Otherwise map the event coordinate to the square.
\r
4696 * The offset boardRect.left or boardRect.top must already have been
\r
4697 * subtracted from x.
\r
4700 EventToSquare(int x)
\r
4707 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4709 x /= (squareSize + lineGap);
\r
4710 if (x >= BOARD_SIZE)
\r
4721 DropEnable dropEnables[] = {
\r
4722 { 'P', DP_Pawn, "Pawn" },
\r
4723 { 'N', DP_Knight, "Knight" },
\r
4724 { 'B', DP_Bishop, "Bishop" },
\r
4725 { 'R', DP_Rook, "Rook" },
\r
4726 { 'Q', DP_Queen, "Queen" },
\r
4730 SetupDropMenu(HMENU hmenu)
\r
4732 int i, count, enable;
\r
4734 extern char white_holding[], black_holding[];
\r
4735 char item[MSG_SIZ];
\r
4737 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4738 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4739 dropEnables[i].piece);
\r
4741 while (p && *p++ == dropEnables[i].piece) count++;
\r
4742 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4743 enable = count > 0 || !appData.testLegality
\r
4744 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4745 && !appData.icsActive);
\r
4746 ModifyMenu(hmenu, dropEnables[i].command,
\r
4747 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4748 dropEnables[i].command, item);
\r
4752 static int fromX = -1, fromY = -1, toX, toY;
\r
4754 /* Event handler for mouse messages */
\r
4756 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4760 static int recursive = 0;
\r
4762 BOOLEAN needsRedraw = FALSE;
\r
4763 BOOLEAN saveAnimate;
\r
4764 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4765 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4766 ChessMove moveType;
\r
4769 if (message == WM_MBUTTONUP) {
\r
4770 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4771 to the middle button: we simulate pressing the left button too!
\r
4773 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4774 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4780 pt.x = LOWORD(lParam);
\r
4781 pt.y = HIWORD(lParam);
\r
4782 x = EventToSquare(pt.x - boardRect.left);
\r
4783 y = EventToSquare(pt.y - boardRect.top);
\r
4784 if (!flipView && y >= 0) {
\r
4785 y = BOARD_HEIGHT - 1 - y;
\r
4787 if (flipView && x >= 0) {
\r
4788 x = BOARD_WIDTH - 1 - x;
\r
4791 switch (message) {
\r
4792 case WM_LBUTTONDOWN:
\r
4793 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4794 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4795 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4796 if(gameInfo.holdingsWidth &&
\r
4797 (WhiteOnMove(currentMove)
\r
4798 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4799 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4800 // click in right holdings, for determining promotion piece
\r
4801 ChessSquare p = boards[currentMove][y][x];
\r
4802 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4803 if(p != EmptySquare) {
\r
4804 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4805 fromX = fromY = -1;
\r
4809 DrawPosition(FALSE, boards[currentMove]);
\r
4813 sameAgain = FALSE;
\r
4815 /* Downclick vertically off board; check if on clock */
\r
4816 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4817 if (gameMode == EditPosition) {
\r
4818 SetWhiteToPlayEvent();
\r
4819 } else if (gameMode == IcsPlayingBlack ||
\r
4820 gameMode == MachinePlaysWhite) {
\r
4822 } else if (gameMode == EditGame) {
\r
4823 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4825 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4826 if (gameMode == EditPosition) {
\r
4827 SetBlackToPlayEvent();
\r
4828 } else if (gameMode == IcsPlayingWhite ||
\r
4829 gameMode == MachinePlaysBlack) {
\r
4831 } else if (gameMode == EditGame) {
\r
4832 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4835 if (!appData.highlightLastMove) {
\r
4836 ClearHighlights();
\r
4837 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4839 fromX = fromY = -1;
\r
4840 dragInfo.start.x = dragInfo.start.y = -1;
\r
4841 dragInfo.from = dragInfo.start;
\r
4843 } else if (x < 0 || y < 0
\r
4844 /* [HGM] block clicks between board and holdings */
\r
4845 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4846 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4847 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4848 /* EditPosition, empty square, or different color piece;
\r
4849 click-click move is possible */
\r
4852 } else if (fromX == x && fromY == y) {
\r
4853 /* Downclick on same square again */
\r
4854 ClearHighlights();
\r
4855 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4856 sameAgain = TRUE;
\r
4857 } else if (fromX != -1 &&
\r
4858 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4860 /* Downclick on different square. */
\r
4861 /* [HGM] if on holdings file, should count as new first click ! */
\r
4862 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4865 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4866 to make sure move is legal before showing promotion popup */
\r
4867 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4868 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4869 fromX = fromY = -1;
\r
4870 ClearHighlights();
\r
4871 DrawPosition(FALSE, boards[currentMove]);
\r
4874 if(moveType != ImpossibleMove) {
\r
4875 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4876 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4877 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4878 appData.alwaysPromoteToQueen) {
\r
4879 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4880 if (!appData.highlightLastMove) {
\r
4881 ClearHighlights();
\r
4882 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4885 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4886 SetHighlights(fromX, fromY, toX, toY);
\r
4887 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4888 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4889 If promotion to Q is legal, all are legal! */
\r
4890 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4891 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4892 // kludge to temporarily execute move on display, wthout promotng yet
\r
4893 promotionChoice = TRUE;
\r
4894 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4895 boards[currentMove][toY][toX] = p;
\r
4896 DrawPosition(FALSE, boards[currentMove]);
\r
4897 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4898 boards[currentMove][toY][toX] = q;
\r
4900 PromotionPopup(hwnd);
\r
4901 } else { /* not a promotion */
\r
4902 if (appData.animate || appData.highlightLastMove) {
\r
4903 SetHighlights(fromX, fromY, toX, toY);
\r
4905 ClearHighlights();
\r
4907 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4908 fromX = fromY = -1;
\r
4909 if (appData.animate && !appData.highlightLastMove) {
\r
4910 ClearHighlights();
\r
4911 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4917 /* [HGM] it seemed that braces were missing here */
\r
4918 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4919 fromX = fromY = -1;
\r
4923 ClearHighlights();
\r
4924 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4926 /* First downclick, or restart on a square with same color piece */
\r
4927 if (!frozen && OKToStartUserMove(x, y)) {
\r
4930 dragInfo.lastpos = pt;
\r
4931 dragInfo.from.x = fromX;
\r
4932 dragInfo.from.y = fromY;
\r
4933 dragInfo.start = dragInfo.from;
\r
4934 SetCapture(hwndMain);
\r
4936 fromX = fromY = -1;
\r
4937 dragInfo.start.x = dragInfo.start.y = -1;
\r
4938 dragInfo.from = dragInfo.start;
\r
4939 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4943 case WM_LBUTTONUP:
\r
4945 if (fromX == -1) break;
\r
4946 if (x == fromX && y == fromY) {
\r
4947 dragInfo.from.x = dragInfo.from.y = -1;
\r
4948 /* Upclick on same square */
\r
4950 /* Clicked same square twice: abort click-click move */
\r
4951 fromX = fromY = -1;
\r
4953 ClearPremoveHighlights();
\r
4955 /* First square clicked: start click-click move */
\r
4956 SetHighlights(fromX, fromY, -1, -1);
\r
4958 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4959 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4960 /* Errant click; ignore */
\r
4963 /* Finish drag move. */
\r
4964 if (appData.debugMode) {
\r
4965 fprintf(debugFP, "release\n");
\r
4967 dragInfo.from.x = dragInfo.from.y = -1;
\r
4970 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4971 appData.animate = appData.animate && !appData.animateDragging;
\r
4972 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4973 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4974 fromX = fromY = -1;
\r
4975 ClearHighlights();
\r
4976 DrawPosition(FALSE, boards[currentMove]);
\r
4979 if(moveType != ImpossibleMove) {
\r
4980 /* [HGM] use move type to determine if move is promotion.
\r
4981 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4982 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4983 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4984 appData.alwaysPromoteToQueen)
\r
4985 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4987 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4988 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4989 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4990 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4991 // kludge to temporarily execute move on display, wthout promotng yet
\r
4992 promotionChoice = TRUE;
\r
4993 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4994 boards[currentMove][toY][toX] = p;
\r
4995 DrawPosition(FALSE, boards[currentMove]);
\r
4996 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4997 boards[currentMove][toY][toX] = q;
\r
5000 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5001 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5003 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5004 appData.animate = saveAnimate;
\r
5005 fromX = fromY = -1;
\r
5006 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5007 ClearHighlights();
\r
5009 if (appData.animate || appData.animateDragging ||
\r
5010 appData.highlightDragging || gotPremove) {
\r
5011 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5014 dragInfo.start.x = dragInfo.start.y = -1;
\r
5015 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5018 case WM_MOUSEMOVE:
\r
5019 if ((appData.animateDragging || appData.highlightDragging)
\r
5020 && (wParam & MK_LBUTTON)
\r
5021 && dragInfo.from.x >= 0)
\r
5023 BOOL full_repaint = FALSE;
\r
5025 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5026 if (appData.animateDragging) {
\r
5027 dragInfo.pos = pt;
\r
5029 if (appData.highlightDragging) {
\r
5030 SetHighlights(fromX, fromY, x, y);
\r
5031 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5032 full_repaint = TRUE;
\r
5036 DrawPosition( full_repaint, NULL);
\r
5038 dragInfo.lastpos = dragInfo.pos;
\r
5042 case WM_MBUTTONDOWN:
\r
5043 case WM_RBUTTONDOWN:
\r
5046 fromX = fromY = -1;
\r
5047 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5048 dragInfo.start.x = dragInfo.start.y = -1;
\r
5049 dragInfo.from = dragInfo.start;
\r
5050 dragInfo.lastpos = dragInfo.pos;
\r
5051 if (appData.highlightDragging) {
\r
5052 ClearHighlights();
\r
5055 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5056 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5057 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5058 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5059 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5062 DrawPosition(TRUE, NULL);
\r
5064 switch (gameMode) {
\r
5065 case EditPosition:
\r
5066 case IcsExamining:
\r
5067 if (x < 0 || y < 0) break;
\r
5070 if (message == WM_MBUTTONDOWN) {
\r
5071 buttonCount = 3; /* even if system didn't think so */
\r
5072 if (wParam & MK_SHIFT)
\r
5073 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5075 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5076 } else { /* message == WM_RBUTTONDOWN */
\r
5078 if (buttonCount == 3) {
\r
5079 if (wParam & MK_SHIFT)
\r
5080 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5082 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5084 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5087 /* Just have one menu, on the right button. Windows users don't
\r
5088 think to try the middle one, and sometimes other software steals
\r
5089 it, or it doesn't really exist. */
\r
5090 if(gameInfo.variant != VariantShogi)
\r
5091 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5093 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5097 case IcsPlayingWhite:
\r
5098 case IcsPlayingBlack:
\r
5100 case MachinePlaysWhite:
\r
5101 case MachinePlaysBlack:
\r
5102 if (appData.testLegality &&
\r
5103 gameInfo.variant != VariantBughouse &&
\r
5104 gameInfo.variant != VariantCrazyhouse) break;
\r
5105 if (x < 0 || y < 0) break;
\r
5108 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5109 SetupDropMenu(hmenu);
\r
5110 MenuPopup(hwnd, pt, hmenu, -1);
\r
5121 /* Preprocess messages for buttons in main window */
\r
5123 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5125 int id = GetWindowLong(hwnd, GWL_ID);
\r
5128 for (i=0; i<N_BUTTONS; i++) {
\r
5129 if (buttonDesc[i].id == id) break;
\r
5131 if (i == N_BUTTONS) return 0;
\r
5132 switch (message) {
\r
5137 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5138 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5145 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5148 if (appData.icsActive) {
\r
5149 if (GetKeyState(VK_SHIFT) < 0) {
\r
5151 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5152 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5156 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5157 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5164 if (appData.icsActive) {
\r
5165 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5166 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5168 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5170 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5171 PopUpMoveDialog((char)wParam);
\r
5177 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5180 /* Process messages for Promotion dialog box */
\r
5182 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5186 switch (message) {
\r
5187 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5188 /* Center the dialog over the application window */
\r
5189 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5190 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5191 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5192 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5193 SW_SHOW : SW_HIDE);
\r
5194 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5195 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5196 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5197 PieceToChar(WhiteAngel) != '~' ||
\r
5198 PieceToChar(BlackAngel) >= 'A' &&
\r
5199 PieceToChar(BlackAngel) != '~' ) ?
\r
5200 SW_SHOW : SW_HIDE);
\r
5201 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5202 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5203 PieceToChar(WhiteMarshall) != '~' ||
\r
5204 PieceToChar(BlackMarshall) >= 'A' &&
\r
5205 PieceToChar(BlackMarshall) != '~' ) ?
\r
5206 SW_SHOW : SW_HIDE);
\r
5207 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5208 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5209 gameInfo.variant != VariantShogi ?
\r
5210 SW_SHOW : SW_HIDE);
\r
5211 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5212 gameInfo.variant != VariantShogi ?
\r
5213 SW_SHOW : SW_HIDE);
\r
5214 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5215 gameInfo.variant == VariantShogi ?
\r
5216 SW_SHOW : SW_HIDE);
\r
5217 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5218 gameInfo.variant == VariantShogi ?
\r
5219 SW_SHOW : SW_HIDE);
\r
5220 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5221 gameInfo.variant == VariantSuper ?
\r
5222 SW_SHOW : SW_HIDE);
\r
5225 case WM_COMMAND: /* message: received a command */
\r
5226 switch (LOWORD(wParam)) {
\r
5228 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5229 ClearHighlights();
\r
5230 DrawPosition(FALSE, NULL);
\r
5233 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5236 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5239 promoChar = PieceToChar(BlackRook);
\r
5242 promoChar = PieceToChar(BlackBishop);
\r
5244 case PB_Chancellor:
\r
5245 promoChar = PieceToChar(BlackMarshall);
\r
5247 case PB_Archbishop:
\r
5248 promoChar = PieceToChar(BlackAngel);
\r
5251 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5256 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5257 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5258 only show the popup when we are already sure the move is valid or
\r
5259 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5260 will figure out it is a promotion from the promoChar. */
\r
5261 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5262 if (!appData.highlightLastMove) {
\r
5263 ClearHighlights();
\r
5264 DrawPosition(FALSE, NULL);
\r
5271 /* Pop up promotion dialog */
\r
5273 PromotionPopup(HWND hwnd)
\r
5277 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5278 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5279 hwnd, (DLGPROC)lpProc);
\r
5280 FreeProcInstance(lpProc);
\r
5283 /* Toggle ShowThinking */
\r
5285 ToggleShowThinking()
\r
5287 appData.showThinking = !appData.showThinking;
\r
5288 ShowThinkingEvent();
\r
5292 LoadGameDialog(HWND hwnd, char* title)
\r
5296 char fileTitle[MSG_SIZ];
\r
5297 f = OpenFileDialog(hwnd, "rb", "",
\r
5298 appData.oldSaveStyle ? "gam" : "pgn",
\r
5300 title, &number, fileTitle, NULL);
\r
5302 cmailMsgLoaded = FALSE;
\r
5303 if (number == 0) {
\r
5304 int error = GameListBuild(f);
\r
5306 DisplayError("Cannot build game list", error);
\r
5307 } else if (!ListEmpty(&gameList) &&
\r
5308 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5309 GameListPopUp(f, fileTitle);
\r
5312 GameListDestroy();
\r
5315 LoadGame(f, number, fileTitle, FALSE);
\r
5320 ChangedConsoleFont()
\r
5323 CHARRANGE tmpsel, sel;
\r
5324 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5325 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5326 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5329 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5330 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5331 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5332 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5333 * size. This was undocumented in the version of MSVC++ that I had
\r
5334 * when I wrote the code, but is apparently documented now.
\r
5336 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5337 cfmt.bCharSet = f->lf.lfCharSet;
\r
5338 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5339 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5340 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5341 /* Why are the following seemingly needed too? */
\r
5342 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5343 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5344 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5346 tmpsel.cpMax = -1; /*999999?*/
\r
5347 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5348 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5349 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5350 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5352 paraf.cbSize = sizeof(paraf);
\r
5353 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5354 paraf.dxStartIndent = 0;
\r
5355 paraf.dxOffset = WRAP_INDENT;
\r
5356 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5357 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5360 /*---------------------------------------------------------------------------*\
\r
5362 * Window Proc for main window
\r
5364 \*---------------------------------------------------------------------------*/
\r
5366 /* Process messages for main window, etc. */
\r
5368 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5371 int wmId, wmEvent;
\r
5375 char fileTitle[MSG_SIZ];
\r
5376 static SnapData sd;
\r
5378 switch (message) {
\r
5380 case WM_PAINT: /* message: repaint portion of window */
\r
5384 case WM_ERASEBKGND:
\r
5385 if (IsIconic(hwnd)) {
\r
5386 /* Cheat; change the message */
\r
5387 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5389 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5393 case WM_LBUTTONDOWN:
\r
5394 case WM_MBUTTONDOWN:
\r
5395 case WM_RBUTTONDOWN:
\r
5396 case WM_LBUTTONUP:
\r
5397 case WM_MBUTTONUP:
\r
5398 case WM_RBUTTONUP:
\r
5399 case WM_MOUSEMOVE:
\r
5400 MouseEvent(hwnd, message, wParam, lParam);
\r
5405 if (appData.icsActive) {
\r
5406 if (wParam == '\t') {
\r
5407 if (GetKeyState(VK_SHIFT) < 0) {
\r
5409 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5410 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5414 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5415 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5419 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5420 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5422 SendMessage(h, message, wParam, lParam);
\r
5424 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5425 PopUpMoveDialog((char)wParam);
\r
5429 case WM_PALETTECHANGED:
\r
5430 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5432 HDC hdc = GetDC(hwndMain);
\r
5433 SelectPalette(hdc, hPal, TRUE);
\r
5434 nnew = RealizePalette(hdc);
\r
5436 paletteChanged = TRUE;
\r
5438 UpdateColors(hdc);
\r
5440 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5443 ReleaseDC(hwnd, hdc);
\r
5447 case WM_QUERYNEWPALETTE:
\r
5448 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5450 HDC hdc = GetDC(hwndMain);
\r
5451 paletteChanged = FALSE;
\r
5452 SelectPalette(hdc, hPal, FALSE);
\r
5453 nnew = RealizePalette(hdc);
\r
5455 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5457 ReleaseDC(hwnd, hdc);
\r
5462 case WM_COMMAND: /* message: command from application menu */
\r
5463 wmId = LOWORD(wParam);
\r
5464 wmEvent = HIWORD(wParam);
\r
5469 AnalysisPopDown();
\r
5472 case IDM_NewGameFRC:
\r
5473 if( NewGameFRC() == 0 ) {
\r
5475 AnalysisPopDown();
\r
5479 case IDM_NewVariant:
\r
5480 NewVariantPopup(hwnd);
\r
5483 case IDM_LoadGame:
\r
5484 LoadGameDialog(hwnd, "Load Game from File");
\r
5487 case IDM_LoadNextGame:
\r
5491 case IDM_LoadPrevGame:
\r
5495 case IDM_ReloadGame:
\r
5499 case IDM_LoadPosition:
\r
5500 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5501 Reset(FALSE, TRUE);
\r
5504 f = OpenFileDialog(hwnd, "rb", "",
\r
5505 appData.oldSaveStyle ? "pos" : "fen",
\r
5507 "Load Position from File", &number, fileTitle, NULL);
\r
5509 LoadPosition(f, number, fileTitle);
\r
5513 case IDM_LoadNextPosition:
\r
5514 ReloadPosition(1);
\r
5517 case IDM_LoadPrevPosition:
\r
5518 ReloadPosition(-1);
\r
5521 case IDM_ReloadPosition:
\r
5522 ReloadPosition(0);
\r
5525 case IDM_SaveGame:
\r
5526 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5527 f = OpenFileDialog(hwnd, "a", defName,
\r
5528 appData.oldSaveStyle ? "gam" : "pgn",
\r
5530 "Save Game to File", NULL, fileTitle, NULL);
\r
5532 SaveGame(f, 0, "");
\r
5536 case IDM_SavePosition:
\r
5537 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5538 f = OpenFileDialog(hwnd, "a", defName,
\r
5539 appData.oldSaveStyle ? "pos" : "fen",
\r
5541 "Save Position to File", NULL, fileTitle, NULL);
\r
5543 SavePosition(f, 0, "");
\r
5547 case IDM_SaveDiagram:
\r
5548 defName = "diagram";
\r
5549 f = OpenFileDialog(hwnd, "wb", defName,
\r
5552 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5558 case IDM_CopyGame:
\r
5559 CopyGameToClipboard();
\r
5562 case IDM_PasteGame:
\r
5563 PasteGameFromClipboard();
\r
5566 case IDM_CopyGameListToClipboard:
\r
5567 CopyGameListToClipboard();
\r
5570 /* [AS] Autodetect FEN or PGN data */
\r
5571 case IDM_PasteAny:
\r
5572 PasteGameOrFENFromClipboard();
\r
5575 /* [AS] Move history */
\r
5576 case IDM_ShowMoveHistory:
\r
5577 if( MoveHistoryIsUp() ) {
\r
5578 MoveHistoryPopDown();
\r
5581 MoveHistoryPopUp();
\r
5585 /* [AS] Eval graph */
\r
5586 case IDM_ShowEvalGraph:
\r
5587 if( EvalGraphIsUp() ) {
\r
5588 EvalGraphPopDown();
\r
5595 /* [AS] Engine output */
\r
5596 case IDM_ShowEngineOutput:
\r
5597 if( EngineOutputIsUp() ) {
\r
5598 EngineOutputPopDown();
\r
5601 EngineOutputPopUp();
\r
5605 /* [AS] User adjudication */
\r
5606 case IDM_UserAdjudication_White:
\r
5607 UserAdjudicationEvent( +1 );
\r
5610 case IDM_UserAdjudication_Black:
\r
5611 UserAdjudicationEvent( -1 );
\r
5614 case IDM_UserAdjudication_Draw:
\r
5615 UserAdjudicationEvent( 0 );
\r
5618 /* [AS] Game list options dialog */
\r
5619 case IDM_GameListOptions:
\r
5620 GameListOptions();
\r
5623 case IDM_CopyPosition:
\r
5624 CopyFENToClipboard();
\r
5627 case IDM_PastePosition:
\r
5628 PasteFENFromClipboard();
\r
5631 case IDM_MailMove:
\r
5635 case IDM_ReloadCMailMsg:
\r
5636 Reset(TRUE, TRUE);
\r
5637 ReloadCmailMsgEvent(FALSE);
\r
5640 case IDM_Minimize:
\r
5641 ShowWindow(hwnd, SW_MINIMIZE);
\r
5648 case IDM_MachineWhite:
\r
5649 MachineWhiteEvent();
\r
5651 * refresh the tags dialog only if it's visible
\r
5653 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5655 tags = PGNTags(&gameInfo);
\r
5656 TagsPopUp(tags, CmailMsg());
\r
5661 case IDM_MachineBlack:
\r
5662 MachineBlackEvent();
\r
5664 * refresh the tags dialog only if it's visible
\r
5666 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5668 tags = PGNTags(&gameInfo);
\r
5669 TagsPopUp(tags, CmailMsg());
\r
5674 case IDM_TwoMachines:
\r
5675 TwoMachinesEvent();
\r
5677 * refresh the tags dialog only if it's visible
\r
5679 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5681 tags = PGNTags(&gameInfo);
\r
5682 TagsPopUp(tags, CmailMsg());
\r
5687 case IDM_AnalysisMode:
\r
5688 if (!first.analysisSupport) {
\r
5689 char buf[MSG_SIZ];
\r
5690 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5691 DisplayError(buf, 0);
\r
5693 if (!appData.showThinking) ToggleShowThinking();
\r
5694 AnalyzeModeEvent();
\r
5698 case IDM_AnalyzeFile:
\r
5699 if (!first.analysisSupport) {
\r
5700 char buf[MSG_SIZ];
\r
5701 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5702 DisplayError(buf, 0);
\r
5704 if (!appData.showThinking) ToggleShowThinking();
\r
5705 AnalyzeFileEvent();
\r
5706 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5707 AnalysisPeriodicEvent(1);
\r
5711 case IDM_IcsClient:
\r
5715 case IDM_EditGame:
\r
5719 case IDM_EditPosition:
\r
5720 EditPositionEvent();
\r
5723 case IDM_Training:
\r
5727 case IDM_ShowGameList:
\r
5728 ShowGameListProc();
\r
5731 case IDM_EditTags:
\r
5735 case IDM_EditComment:
\r
5736 if (commentDialogUp && editComment) {
\r
5739 EditCommentEvent();
\r
5759 case IDM_CallFlag:
\r
5779 case IDM_StopObserving:
\r
5780 StopObservingEvent();
\r
5783 case IDM_StopExamining:
\r
5784 StopExaminingEvent();
\r
5787 case IDM_TypeInMove:
\r
5788 PopUpMoveDialog('\000');
\r
5791 case IDM_TypeInName:
\r
5792 PopUpNameDialog('\000');
\r
5795 case IDM_Backward:
\r
5797 SetFocus(hwndMain);
\r
5802 SetFocus(hwndMain);
\r
5807 SetFocus(hwndMain);
\r
5812 SetFocus(hwndMain);
\r
5819 case IDM_TruncateGame:
\r
5820 TruncateGameEvent();
\r
5827 case IDM_RetractMove:
\r
5828 RetractMoveEvent();
\r
5831 case IDM_FlipView:
\r
5832 flipView = !flipView;
\r
5833 DrawPosition(FALSE, NULL);
\r
5836 case IDM_FlipClock:
\r
5837 flipClock = !flipClock;
\r
5838 DisplayBothClocks();
\r
5841 case IDM_GeneralOptions:
\r
5842 GeneralOptionsPopup(hwnd);
\r
5843 DrawPosition(TRUE, NULL);
\r
5846 case IDM_BoardOptions:
\r
5847 BoardOptionsPopup(hwnd);
\r
5850 case IDM_EnginePlayOptions:
\r
5851 EnginePlayOptionsPopup(hwnd);
\r
5854 case IDM_OptionsUCI:
\r
5855 UciOptionsPopup(hwnd);
\r
5858 case IDM_IcsOptions:
\r
5859 IcsOptionsPopup(hwnd);
\r
5863 FontsOptionsPopup(hwnd);
\r
5867 SoundOptionsPopup(hwnd);
\r
5870 case IDM_CommPort:
\r
5871 CommPortOptionsPopup(hwnd);
\r
5874 case IDM_LoadOptions:
\r
5875 LoadOptionsPopup(hwnd);
\r
5878 case IDM_SaveOptions:
\r
5879 SaveOptionsPopup(hwnd);
\r
5882 case IDM_TimeControl:
\r
5883 TimeControlOptionsPopup(hwnd);
\r
5886 case IDM_SaveSettings:
\r
5887 SaveSettings(settingsFileName);
\r
5890 case IDM_SaveSettingsOnExit:
\r
5891 saveSettingsOnExit = !saveSettingsOnExit;
\r
5892 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5893 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5894 MF_CHECKED : MF_UNCHECKED));
\r
5905 case IDM_AboutGame:
\r
5910 appData.debugMode = !appData.debugMode;
\r
5911 if (appData.debugMode) {
\r
5912 char dir[MSG_SIZ];
\r
5913 GetCurrentDirectory(MSG_SIZ, dir);
\r
5914 SetCurrentDirectory(installDir);
\r
5915 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5916 SetCurrentDirectory(dir);
\r
5917 setbuf(debugFP, NULL);
\r
5924 case IDM_HELPCONTENTS:
\r
5925 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5926 MessageBox (GetFocus(),
\r
5927 "Unable to activate help",
\r
5928 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5932 case IDM_HELPSEARCH:
\r
5933 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5934 MessageBox (GetFocus(),
\r
5935 "Unable to activate help",
\r
5936 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5940 case IDM_HELPHELP:
\r
5941 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5942 MessageBox (GetFocus(),
\r
5943 "Unable to activate help",
\r
5944 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5949 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5951 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5952 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5953 FreeProcInstance(lpProc);
\r
5956 case IDM_DirectCommand1:
\r
5957 AskQuestionEvent("Direct Command",
\r
5958 "Send to chess program:", "", "1");
\r
5960 case IDM_DirectCommand2:
\r
5961 AskQuestionEvent("Direct Command",
\r
5962 "Send to second chess program:", "", "2");
\r
5965 case EP_WhitePawn:
\r
5966 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5967 fromX = fromY = -1;
\r
5970 case EP_WhiteKnight:
\r
5971 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5972 fromX = fromY = -1;
\r
5975 case EP_WhiteBishop:
\r
5976 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5977 fromX = fromY = -1;
\r
5980 case EP_WhiteRook:
\r
5981 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5982 fromX = fromY = -1;
\r
5985 case EP_WhiteQueen:
\r
5986 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5987 fromX = fromY = -1;
\r
5990 case EP_WhiteFerz:
\r
5991 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5992 fromX = fromY = -1;
\r
5995 case EP_WhiteWazir:
\r
5996 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5997 fromX = fromY = -1;
\r
6000 case EP_WhiteAlfil:
\r
6001 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6002 fromX = fromY = -1;
\r
6005 case EP_WhiteCannon:
\r
6006 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6007 fromX = fromY = -1;
\r
6010 case EP_WhiteCardinal:
\r
6011 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6012 fromX = fromY = -1;
\r
6015 case EP_WhiteMarshall:
\r
6016 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6017 fromX = fromY = -1;
\r
6020 case EP_WhiteKing:
\r
6021 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6022 fromX = fromY = -1;
\r
6025 case EP_BlackPawn:
\r
6026 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6027 fromX = fromY = -1;
\r
6030 case EP_BlackKnight:
\r
6031 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6032 fromX = fromY = -1;
\r
6035 case EP_BlackBishop:
\r
6036 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6037 fromX = fromY = -1;
\r
6040 case EP_BlackRook:
\r
6041 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6042 fromX = fromY = -1;
\r
6045 case EP_BlackQueen:
\r
6046 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6047 fromX = fromY = -1;
\r
6050 case EP_BlackFerz:
\r
6051 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6052 fromX = fromY = -1;
\r
6055 case EP_BlackWazir:
\r
6056 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6057 fromX = fromY = -1;
\r
6060 case EP_BlackAlfil:
\r
6061 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6062 fromX = fromY = -1;
\r
6065 case EP_BlackCannon:
\r
6066 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6067 fromX = fromY = -1;
\r
6070 case EP_BlackCardinal:
\r
6071 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_BlackMarshall:
\r
6076 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_BlackKing:
\r
6081 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6085 case EP_EmptySquare:
\r
6086 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6090 case EP_ClearBoard:
\r
6091 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6096 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6101 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6106 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6111 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6116 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6121 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6126 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6131 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6132 fromX = fromY = -1;
\r
6136 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6137 fromX = fromY = -1;
\r
6141 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6147 case CLOCK_TIMER_ID:
\r
6148 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6149 clockTimerEvent = 0;
\r
6150 DecrementClocks(); /* call into back end */
\r
6152 case LOAD_GAME_TIMER_ID:
\r
6153 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6154 loadGameTimerEvent = 0;
\r
6155 AutoPlayGameLoop(); /* call into back end */
\r
6157 case ANALYSIS_TIMER_ID:
\r
6158 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
6159 appData.periodicUpdates) {
\r
6160 AnalysisPeriodicEvent(0);
\r
6162 KillTimer(hwnd, analysisTimerEvent);
\r
6163 analysisTimerEvent = 0;
\r
6166 case DELAYED_TIMER_ID:
\r
6167 KillTimer(hwnd, delayedTimerEvent);
\r
6168 delayedTimerEvent = 0;
\r
6169 delayedTimerCallback();
\r
6174 case WM_USER_Input:
\r
6175 InputEvent(hwnd, message, wParam, lParam);
\r
6178 /* [AS] Also move "attached" child windows */
\r
6179 case WM_WINDOWPOSCHANGING:
\r
6180 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6181 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6183 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6184 /* Window is moving */
\r
6187 GetWindowRect( hwnd, &rcMain );
\r
6189 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6190 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6191 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6196 /* [AS] Snapping */
\r
6197 case WM_ENTERSIZEMOVE:
\r
6198 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6199 if (hwnd == hwndMain) {
\r
6200 doingSizing = TRUE;
\r
6203 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6207 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6208 if (hwnd == hwndMain) {
\r
6209 lastSizing = wParam;
\r
6214 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6215 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6217 case WM_EXITSIZEMOVE:
\r
6218 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6219 if (hwnd == hwndMain) {
\r
6221 doingSizing = FALSE;
\r
6222 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6223 GetClientRect(hwnd, &client);
\r
6224 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6226 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6228 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6231 case WM_DESTROY: /* message: window being destroyed */
\r
6232 PostQuitMessage(0);
\r
6236 if (hwnd == hwndMain) {
\r
6241 default: /* Passes it on if unprocessed */
\r
6242 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6247 /*---------------------------------------------------------------------------*\
\r
6249 * Misc utility routines
\r
6251 \*---------------------------------------------------------------------------*/
\r
6254 * Decent random number generator, at least not as bad as Windows
\r
6255 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6257 unsigned int randstate;
\r
6262 randstate = randstate * 1664525 + 1013904223;
\r
6263 return (int) randstate & 0x7fffffff;
\r
6267 mysrandom(unsigned int seed)
\r
6274 * returns TRUE if user selects a different color, FALSE otherwise
\r
6278 ChangeColor(HWND hwnd, COLORREF *which)
\r
6280 static BOOL firstTime = TRUE;
\r
6281 static DWORD customColors[16];
\r
6283 COLORREF newcolor;
\r
6288 /* Make initial colors in use available as custom colors */
\r
6289 /* Should we put the compiled-in defaults here instead? */
\r
6291 customColors[i++] = lightSquareColor & 0xffffff;
\r
6292 customColors[i++] = darkSquareColor & 0xffffff;
\r
6293 customColors[i++] = whitePieceColor & 0xffffff;
\r
6294 customColors[i++] = blackPieceColor & 0xffffff;
\r
6295 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6296 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6298 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6299 customColors[i++] = textAttribs[ccl].color;
\r
6301 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6302 firstTime = FALSE;
\r
6305 cc.lStructSize = sizeof(cc);
\r
6306 cc.hwndOwner = hwnd;
\r
6307 cc.hInstance = NULL;
\r
6308 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6309 cc.lpCustColors = (LPDWORD) customColors;
\r
6310 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6312 if (!ChooseColor(&cc)) return FALSE;
\r
6314 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6315 if (newcolor == *which) return FALSE;
\r
6316 *which = newcolor;
\r
6320 InitDrawingColors();
\r
6321 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6326 MyLoadSound(MySound *ms)
\r
6332 if (ms->data) free(ms->data);
\r
6335 switch (ms->name[0]) {
\r
6341 /* System sound from Control Panel. Don't preload here. */
\r
6345 if (ms->name[1] == NULLCHAR) {
\r
6346 /* "!" alone = silence */
\r
6349 /* Builtin wave resource. Error if not found. */
\r
6350 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6351 if (h == NULL) break;
\r
6352 ms->data = (void *)LoadResource(hInst, h);
\r
6353 if (h == NULL) break;
\r
6358 /* .wav file. Error if not found. */
\r
6359 f = fopen(ms->name, "rb");
\r
6360 if (f == NULL) break;
\r
6361 if (fstat(fileno(f), &st) < 0) break;
\r
6362 ms->data = malloc(st.st_size);
\r
6363 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6369 char buf[MSG_SIZ];
\r
6370 sprintf(buf, "Error loading sound %s", ms->name);
\r
6371 DisplayError(buf, GetLastError());
\r
6377 MyPlaySound(MySound *ms)
\r
6379 BOOLEAN ok = FALSE;
\r
6380 switch (ms->name[0]) {
\r
6386 /* System sound from Control Panel (deprecated feature).
\r
6387 "$" alone or an unset sound name gets default beep (still in use). */
\r
6388 if (ms->name[1]) {
\r
6389 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6391 if (!ok) ok = MessageBeep(MB_OK);
\r
6394 /* Builtin wave resource, or "!" alone for silence */
\r
6395 if (ms->name[1]) {
\r
6396 if (ms->data == NULL) return FALSE;
\r
6397 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6403 /* .wav file. Error if not found. */
\r
6404 if (ms->data == NULL) return FALSE;
\r
6405 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6408 /* Don't print an error: this can happen innocently if the sound driver
\r
6409 is busy; for instance, if another instance of WinBoard is playing
\r
6410 a sound at about the same time. */
\r
6413 char buf[MSG_SIZ];
\r
6414 sprintf(buf, "Error playing sound %s", ms->name);
\r
6415 DisplayError(buf, GetLastError());
\r
6423 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6426 OPENFILENAME *ofn;
\r
6427 static UINT *number; /* gross that this is static */
\r
6429 switch (message) {
\r
6430 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6431 /* Center the dialog over the application window */
\r
6432 ofn = (OPENFILENAME *) lParam;
\r
6433 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6434 number = (UINT *) ofn->lCustData;
\r
6435 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6439 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6440 return FALSE; /* Allow for further processing */
\r
6443 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6444 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6446 return FALSE; /* Allow for further processing */
\r
6452 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6454 static UINT *number;
\r
6455 OPENFILENAME *ofname;
\r
6458 case WM_INITDIALOG:
\r
6459 ofname = (OPENFILENAME *)lParam;
\r
6460 number = (UINT *)(ofname->lCustData);
\r
6463 ofnot = (OFNOTIFY *)lParam;
\r
6464 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6465 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6474 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6475 char *nameFilt, char *dlgTitle, UINT *number,
\r
6476 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6478 OPENFILENAME openFileName;
\r
6479 char buf1[MSG_SIZ];
\r
6482 if (fileName == NULL) fileName = buf1;
\r
6483 if (defName == NULL) {
\r
6484 strcpy(fileName, "*.");
\r
6485 strcat(fileName, defExt);
\r
6487 strcpy(fileName, defName);
\r
6489 if (fileTitle) strcpy(fileTitle, "");
\r
6490 if (number) *number = 0;
\r
6492 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6493 openFileName.hwndOwner = hwnd;
\r
6494 openFileName.hInstance = (HANDLE) hInst;
\r
6495 openFileName.lpstrFilter = nameFilt;
\r
6496 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6497 openFileName.nMaxCustFilter = 0L;
\r
6498 openFileName.nFilterIndex = 1L;
\r
6499 openFileName.lpstrFile = fileName;
\r
6500 openFileName.nMaxFile = MSG_SIZ;
\r
6501 openFileName.lpstrFileTitle = fileTitle;
\r
6502 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6503 openFileName.lpstrInitialDir = NULL;
\r
6504 openFileName.lpstrTitle = dlgTitle;
\r
6505 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6506 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6507 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6508 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6509 openFileName.nFileOffset = 0;
\r
6510 openFileName.nFileExtension = 0;
\r
6511 openFileName.lpstrDefExt = defExt;
\r
6512 openFileName.lCustData = (LONG) number;
\r
6513 openFileName.lpfnHook = oldDialog ?
\r
6514 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6515 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6517 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6518 GetOpenFileName(&openFileName)) {
\r
6519 /* open the file */
\r
6520 f = fopen(openFileName.lpstrFile, write);
\r
6522 MessageBox(hwnd, "File open failed", NULL,
\r
6523 MB_OK|MB_ICONEXCLAMATION);
\r
6527 int err = CommDlgExtendedError();
\r
6528 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6537 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6539 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6542 * Get the first pop-up menu in the menu template. This is the
\r
6543 * menu that TrackPopupMenu displays.
\r
6545 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6547 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6550 * TrackPopup uses screen coordinates, so convert the
\r
6551 * coordinates of the mouse click to screen coordinates.
\r
6553 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6555 /* Draw and track the floating pop-up menu. */
\r
6556 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6557 pt.x, pt.y, 0, hwnd, NULL);
\r
6559 /* Destroy the menu.*/
\r
6560 DestroyMenu(hmenu);
\r
6565 int sizeX, sizeY, newSizeX, newSizeY;
\r
6567 } ResizeEditPlusButtonsClosure;
\r
6570 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6572 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6576 if (hChild == cl->hText) return TRUE;
\r
6577 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6578 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6579 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6580 ScreenToClient(cl->hDlg, &pt);
\r
6581 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6582 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6586 /* Resize a dialog that has a (rich) edit field filling most of
\r
6587 the top, with a row of buttons below */
\r
6589 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6592 int newTextHeight, newTextWidth;
\r
6593 ResizeEditPlusButtonsClosure cl;
\r
6595 /*if (IsIconic(hDlg)) return;*/
\r
6596 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6598 cl.hdwp = BeginDeferWindowPos(8);
\r
6600 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6601 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6602 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6603 if (newTextHeight < 0) {
\r
6604 newSizeY += -newTextHeight;
\r
6605 newTextHeight = 0;
\r
6607 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6608 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6614 cl.newSizeX = newSizeX;
\r
6615 cl.newSizeY = newSizeY;
\r
6616 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6618 EndDeferWindowPos(cl.hdwp);
\r
6621 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6623 RECT rChild, rParent;
\r
6624 int wChild, hChild, wParent, hParent;
\r
6625 int wScreen, hScreen, xNew, yNew;
\r
6628 /* Get the Height and Width of the child window */
\r
6629 GetWindowRect (hwndChild, &rChild);
\r
6630 wChild = rChild.right - rChild.left;
\r
6631 hChild = rChild.bottom - rChild.top;
\r
6633 /* Get the Height and Width of the parent window */
\r
6634 GetWindowRect (hwndParent, &rParent);
\r
6635 wParent = rParent.right - rParent.left;
\r
6636 hParent = rParent.bottom - rParent.top;
\r
6638 /* Get the display limits */
\r
6639 hdc = GetDC (hwndChild);
\r
6640 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6641 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6642 ReleaseDC(hwndChild, hdc);
\r
6644 /* Calculate new X position, then adjust for screen */
\r
6645 xNew = rParent.left + ((wParent - wChild) /2);
\r
6648 } else if ((xNew+wChild) > wScreen) {
\r
6649 xNew = wScreen - wChild;
\r
6652 /* Calculate new Y position, then adjust for screen */
\r
6654 yNew = rParent.top + ((hParent - hChild) /2);
\r
6657 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6662 } else if ((yNew+hChild) > hScreen) {
\r
6663 yNew = hScreen - hChild;
\r
6666 /* Set it, and return */
\r
6667 return SetWindowPos (hwndChild, NULL,
\r
6668 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6671 /* Center one window over another */
\r
6672 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6674 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6677 /*---------------------------------------------------------------------------*\
\r
6679 * Startup Dialog functions
\r
6681 \*---------------------------------------------------------------------------*/
\r
6683 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6685 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6687 while (*cd != NULL) {
\r
6688 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6694 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6696 char buf1[ARG_MAX];
\r
6699 if (str[0] == '@') {
\r
6700 FILE* f = fopen(str + 1, "r");
\r
6702 DisplayFatalError(str + 1, errno, 2);
\r
6705 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6707 buf1[len] = NULLCHAR;
\r
6711 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6714 char buf[MSG_SIZ];
\r
6715 char *end = strchr(str, '\n');
\r
6716 if (end == NULL) return;
\r
6717 memcpy(buf, str, end - str);
\r
6718 buf[end - str] = NULLCHAR;
\r
6719 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6725 SetStartupDialogEnables(HWND hDlg)
\r
6727 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6728 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6729 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6730 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6731 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6732 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6733 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6734 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6735 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6736 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6737 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6738 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6739 IsDlgButtonChecked(hDlg, OPT_View));
\r
6743 QuoteForFilename(char *filename)
\r
6745 int dquote, space;
\r
6746 dquote = strchr(filename, '"') != NULL;
\r
6747 space = strchr(filename, ' ') != NULL;
\r
6748 if (dquote || space) {
\r
6760 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6762 char buf[MSG_SIZ];
\r
6765 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6766 q = QuoteForFilename(nthcp);
\r
6767 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6768 if (*nthdir != NULLCHAR) {
\r
6769 q = QuoteForFilename(nthdir);
\r
6770 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6772 if (*nthcp == NULLCHAR) {
\r
6773 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6774 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6775 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6776 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6781 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6783 char buf[MSG_SIZ];
\r
6787 switch (message) {
\r
6788 case WM_INITDIALOG:
\r
6789 /* Center the dialog */
\r
6790 CenterWindow (hDlg, GetDesktopWindow());
\r
6791 /* Initialize the dialog items */
\r
6792 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6793 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6794 firstChessProgramNames);
\r
6795 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6796 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6797 secondChessProgramNames);
\r
6798 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6799 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6800 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6801 if (*appData.icsHelper != NULLCHAR) {
\r
6802 char *q = QuoteForFilename(appData.icsHelper);
\r
6803 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6805 if (*appData.icsHost == NULLCHAR) {
\r
6806 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6807 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6808 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6809 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6810 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6813 if (appData.icsActive) {
\r
6814 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6816 else if (appData.noChessProgram) {
\r
6817 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6820 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6823 SetStartupDialogEnables(hDlg);
\r
6827 switch (LOWORD(wParam)) {
\r
6829 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6830 strcpy(buf, "/fcp=");
\r
6831 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6833 ParseArgs(StringGet, &p);
\r
6834 strcpy(buf, "/scp=");
\r
6835 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6837 ParseArgs(StringGet, &p);
\r
6838 appData.noChessProgram = FALSE;
\r
6839 appData.icsActive = FALSE;
\r
6840 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6841 strcpy(buf, "/ics /icshost=");
\r
6842 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6844 ParseArgs(StringGet, &p);
\r
6845 if (appData.zippyPlay) {
\r
6846 strcpy(buf, "/fcp=");
\r
6847 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6849 ParseArgs(StringGet, &p);
\r
6851 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6852 appData.noChessProgram = TRUE;
\r
6853 appData.icsActive = FALSE;
\r
6855 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6856 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6859 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6860 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6862 ParseArgs(StringGet, &p);
\r
6864 EndDialog(hDlg, TRUE);
\r
6871 case IDM_HELPCONTENTS:
\r
6872 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6873 MessageBox (GetFocus(),
\r
6874 "Unable to activate help",
\r
6875 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6880 SetStartupDialogEnables(hDlg);
\r
6888 /*---------------------------------------------------------------------------*\
\r
6890 * About box dialog functions
\r
6892 \*---------------------------------------------------------------------------*/
\r
6894 /* Process messages for "About" dialog box */
\r
6896 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6898 switch (message) {
\r
6899 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6900 /* Center the dialog over the application window */
\r
6901 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6902 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6905 case WM_COMMAND: /* message: received a command */
\r
6906 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6907 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6908 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6916 /*---------------------------------------------------------------------------*\
\r
6918 * Comment Dialog functions
\r
6920 \*---------------------------------------------------------------------------*/
\r
6923 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6925 static HANDLE hwndText = NULL;
\r
6926 int len, newSizeX, newSizeY, flags;
\r
6927 static int sizeX, sizeY;
\r
6932 switch (message) {
\r
6933 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6934 /* Initialize the dialog items */
\r
6935 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6936 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6937 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6938 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6939 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6940 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6941 SetWindowText(hDlg, commentTitle);
\r
6942 if (editComment) {
\r
6943 SetFocus(hwndText);
\r
6945 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6947 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6948 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6949 MAKELPARAM(FALSE, 0));
\r
6950 /* Size and position the dialog */
\r
6951 if (!commentDialog) {
\r
6952 commentDialog = hDlg;
\r
6953 flags = SWP_NOZORDER;
\r
6954 GetClientRect(hDlg, &rect);
\r
6955 sizeX = rect.right;
\r
6956 sizeY = rect.bottom;
\r
6957 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6958 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6959 WINDOWPLACEMENT wp;
\r
6960 EnsureOnScreen(&commentX, &commentY);
\r
6961 wp.length = sizeof(WINDOWPLACEMENT);
\r
6963 wp.showCmd = SW_SHOW;
\r
6964 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6965 wp.rcNormalPosition.left = commentX;
\r
6966 wp.rcNormalPosition.right = commentX + commentW;
\r
6967 wp.rcNormalPosition.top = commentY;
\r
6968 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6969 SetWindowPlacement(hDlg, &wp);
\r
6971 GetClientRect(hDlg, &rect);
\r
6972 newSizeX = rect.right;
\r
6973 newSizeY = rect.bottom;
\r
6974 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6975 newSizeX, newSizeY);
\r
6982 case WM_COMMAND: /* message: received a command */
\r
6983 switch (LOWORD(wParam)) {
\r
6985 if (editComment) {
\r
6987 /* Read changed options from the dialog box */
\r
6988 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6989 len = GetWindowTextLength(hwndText);
\r
6990 str = (char *) malloc(len + 1);
\r
6991 GetWindowText(hwndText, str, len + 1);
\r
7000 ReplaceComment(commentIndex, str);
\r
7007 case OPT_CancelComment:
\r
7011 case OPT_ClearComment:
\r
7012 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7015 case OPT_EditComment:
\r
7016 EditCommentEvent();
\r
7025 newSizeX = LOWORD(lParam);
\r
7026 newSizeY = HIWORD(lParam);
\r
7027 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7032 case WM_GETMINMAXINFO:
\r
7033 /* Prevent resizing window too small */
\r
7034 mmi = (MINMAXINFO *) lParam;
\r
7035 mmi->ptMinTrackSize.x = 100;
\r
7036 mmi->ptMinTrackSize.y = 100;
\r
7043 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7048 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7050 if (str == NULL) str = "";
\r
7051 p = (char *) malloc(2 * strlen(str) + 2);
\r
7054 if (*str == '\n') *q++ = '\r';
\r
7058 if (commentText != NULL) free(commentText);
\r
7060 commentIndex = index;
\r
7061 commentTitle = title;
\r
7063 editComment = edit;
\r
7065 if (commentDialog) {
\r
7066 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7067 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7069 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7070 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7071 hwndMain, (DLGPROC)lpProc);
\r
7072 FreeProcInstance(lpProc);
\r
7074 commentDialogUp = TRUE;
\r
7078 /*---------------------------------------------------------------------------*\
\r
7080 * Type-in move dialog functions
\r
7082 \*---------------------------------------------------------------------------*/
\r
7085 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7087 char move[MSG_SIZ];
\r
7089 ChessMove moveType;
\r
7090 int fromX, fromY, toX, toY;
\r
7093 switch (message) {
\r
7094 case WM_INITDIALOG:
\r
7095 move[0] = (char) lParam;
\r
7096 move[1] = NULLCHAR;
\r
7097 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7098 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7099 SetWindowText(hInput, move);
\r
7101 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7105 switch (LOWORD(wParam)) {
\r
7107 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7108 gameMode != Training) {
\r
7109 DisplayMoveError("Displayed move is not current");
\r
7111 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7112 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7113 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7114 if (gameMode != Training)
\r
7115 forwardMostMove = currentMove;
\r
7116 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7118 DisplayMoveError("Could not parse move");
\r
7121 EndDialog(hDlg, TRUE);
\r
7124 EndDialog(hDlg, FALSE);
\r
7135 PopUpMoveDialog(char firstchar)
\r
7139 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7140 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7141 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7142 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7143 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7144 gameMode == Training) {
\r
7145 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7146 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7147 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7148 FreeProcInstance(lpProc);
\r
7152 /*---------------------------------------------------------------------------*\
\r
7154 * Type-in name dialog functions
\r
7156 \*---------------------------------------------------------------------------*/
\r
7159 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7161 char move[MSG_SIZ];
\r
7164 switch (message) {
\r
7165 case WM_INITDIALOG:
\r
7166 move[0] = (char) lParam;
\r
7167 move[1] = NULLCHAR;
\r
7168 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7169 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7170 SetWindowText(hInput, move);
\r
7172 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7176 switch (LOWORD(wParam)) {
\r
7178 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7179 appData.userName = strdup(move);
\r
7181 EndDialog(hDlg, TRUE);
\r
7184 EndDialog(hDlg, FALSE);
\r
7195 PopUpNameDialog(char firstchar)
\r
7199 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7200 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7201 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7202 FreeProcInstance(lpProc);
\r
7205 /*---------------------------------------------------------------------------*\
\r
7209 \*---------------------------------------------------------------------------*/
\r
7211 /* Nonmodal error box */
\r
7212 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7213 WPARAM wParam, LPARAM lParam);
\r
7216 ErrorPopUp(char *title, char *content)
\r
7220 BOOLEAN modal = hwndMain == NULL;
\r
7238 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7239 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7242 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7244 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7245 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7246 hwndMain, (DLGPROC)lpProc);
\r
7247 FreeProcInstance(lpProc);
\r
7254 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7255 if (errorDialog == NULL) return;
\r
7256 DestroyWindow(errorDialog);
\r
7257 errorDialog = NULL;
\r
7261 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7266 switch (message) {
\r
7267 case WM_INITDIALOG:
\r
7268 GetWindowRect(hDlg, &rChild);
\r
7271 SetWindowPos(hDlg, NULL, rChild.left,
\r
7272 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7273 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7277 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7278 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7279 and it doesn't work when you resize the dialog.
\r
7280 For now, just give it a default position.
\r
7282 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7284 errorDialog = hDlg;
\r
7285 SetWindowText(hDlg, errorTitle);
\r
7286 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7287 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7291 switch (LOWORD(wParam)) {
\r
7294 if (errorDialog == hDlg) errorDialog = NULL;
\r
7295 DestroyWindow(hDlg);
\r
7307 HWND gothicDialog = NULL;
\r
7310 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7314 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7316 switch (message) {
\r
7317 case WM_INITDIALOG:
\r
7318 GetWindowRect(hDlg, &rChild);
\r
7320 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7324 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7325 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7326 and it doesn't work when you resize the dialog.
\r
7327 For now, just give it a default position.
\r
7329 gothicDialog = hDlg;
\r
7330 SetWindowText(hDlg, errorTitle);
\r
7331 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7332 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7336 switch (LOWORD(wParam)) {
\r
7339 if (errorDialog == hDlg) errorDialog = NULL;
\r
7340 DestroyWindow(hDlg);
\r
7352 GothicPopUp(char *title, VariantClass variant)
\r
7356 BOOLEAN modal = hwndMain == NULL;
\r
7357 static char *lastTitle;
\r
7359 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7360 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7362 if(lastTitle != title && gothicDialog != NULL) {
\r
7363 DestroyWindow(gothicDialog);
\r
7364 gothicDialog = NULL;
\r
7366 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7367 title = lastTitle;
\r
7368 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7369 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7370 hwndMain, (DLGPROC)lpProc);
\r
7371 FreeProcInstance(lpProc);
\r
7376 /*---------------------------------------------------------------------------*\
\r
7378 * Ics Interaction console functions
\r
7380 \*---------------------------------------------------------------------------*/
\r
7382 #define HISTORY_SIZE 64
\r
7383 static char *history[HISTORY_SIZE];
\r
7384 int histIn = 0, histP = 0;
\r
7387 SaveInHistory(char *cmd)
\r
7389 if (history[histIn] != NULL) {
\r
7390 free(history[histIn]);
\r
7391 history[histIn] = NULL;
\r
7393 if (*cmd == NULLCHAR) return;
\r
7394 history[histIn] = StrSave(cmd);
\r
7395 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7396 if (history[histIn] != NULL) {
\r
7397 free(history[histIn]);
\r
7398 history[histIn] = NULL;
\r
7404 PrevInHistory(char *cmd)
\r
7407 if (histP == histIn) {
\r
7408 if (history[histIn] != NULL) free(history[histIn]);
\r
7409 history[histIn] = StrSave(cmd);
\r
7411 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7412 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7414 return history[histP];
\r
7420 if (histP == histIn) return NULL;
\r
7421 histP = (histP + 1) % HISTORY_SIZE;
\r
7422 return history[histP];
\r
7429 BOOLEAN immediate;
\r
7430 } IcsTextMenuEntry;
\r
7431 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7432 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7435 ParseIcsTextMenu(char *icsTextMenuString)
\r
7438 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7439 char *p = icsTextMenuString;
\r
7440 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7443 if (e->command != NULL) {
\r
7445 e->command = NULL;
\r
7449 e = icsTextMenuEntry;
\r
7450 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7451 if (*p == ';' || *p == '\n') {
\r
7452 e->item = strdup("-");
\r
7453 e->command = NULL;
\r
7455 } else if (*p == '-') {
\r
7456 e->item = strdup("-");
\r
7457 e->command = NULL;
\r
7461 char *q, *r, *s, *t;
\r
7463 q = strchr(p, ',');
\r
7464 if (q == NULL) break;
\r
7466 r = strchr(q + 1, ',');
\r
7467 if (r == NULL) break;
\r
7469 s = strchr(r + 1, ',');
\r
7470 if (s == NULL) break;
\r
7473 t = strchr(s + 1, c);
\r
7476 t = strchr(s + 1, c);
\r
7478 if (t != NULL) *t = NULLCHAR;
\r
7479 e->item = strdup(p);
\r
7480 e->command = strdup(q + 1);
\r
7481 e->getname = *(r + 1) != '0';
\r
7482 e->immediate = *(s + 1) != '0';
\r
7486 if (t == NULL) break;
\r
7495 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7499 hmenu = LoadMenu(hInst, "TextMenu");
\r
7500 h = GetSubMenu(hmenu, 0);
\r
7502 if (strcmp(e->item, "-") == 0) {
\r
7503 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7505 if (e->item[0] == '|') {
\r
7506 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7507 IDM_CommandX + i, &e->item[1]);
\r
7509 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7518 WNDPROC consoleTextWindowProc;
\r
7521 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7523 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7524 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7528 SetWindowText(hInput, command);
\r
7530 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7532 sel.cpMin = 999999;
\r
7533 sel.cpMax = 999999;
\r
7534 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7539 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7540 if (sel.cpMin == sel.cpMax) {
\r
7541 /* Expand to surrounding word */
\r
7544 tr.chrg.cpMax = sel.cpMin;
\r
7545 tr.chrg.cpMin = --sel.cpMin;
\r
7546 if (sel.cpMin < 0) break;
\r
7547 tr.lpstrText = name;
\r
7548 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7549 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7553 tr.chrg.cpMin = sel.cpMax;
\r
7554 tr.chrg.cpMax = ++sel.cpMax;
\r
7555 tr.lpstrText = name;
\r
7556 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7557 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7560 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7561 MessageBeep(MB_ICONEXCLAMATION);
\r
7565 tr.lpstrText = name;
\r
7566 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7568 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7569 MessageBeep(MB_ICONEXCLAMATION);
\r
7572 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7575 sprintf(buf, "%s %s", command, name);
\r
7576 SetWindowText(hInput, buf);
\r
7577 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7579 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7580 SetWindowText(hInput, buf);
\r
7581 sel.cpMin = 999999;
\r
7582 sel.cpMax = 999999;
\r
7583 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7589 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7594 switch (message) {
\r
7596 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7599 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7602 sel.cpMin = 999999;
\r
7603 sel.cpMax = 999999;
\r
7604 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7605 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7610 if (wParam == '\t') {
\r
7611 if (GetKeyState(VK_SHIFT) < 0) {
\r
7613 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7614 if (buttonDesc[0].hwnd) {
\r
7615 SetFocus(buttonDesc[0].hwnd);
\r
7617 SetFocus(hwndMain);
\r
7621 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7624 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7626 SendMessage(hInput, message, wParam, lParam);
\r
7630 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7632 return SendMessage(hInput, message, wParam, lParam);
\r
7633 case WM_MBUTTONDOWN:
\r
7634 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7635 case WM_RBUTTONDOWN:
\r
7636 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7637 /* Move selection here if it was empty */
\r
7639 pt.x = LOWORD(lParam);
\r
7640 pt.y = HIWORD(lParam);
\r
7641 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7642 if (sel.cpMin == sel.cpMax) {
\r
7643 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7644 sel.cpMax = sel.cpMin;
\r
7645 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7647 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7650 case WM_RBUTTONUP:
\r
7651 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7652 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7653 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7656 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7657 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7658 if (sel.cpMin == sel.cpMax) {
\r
7659 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7660 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7662 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7663 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7665 pt.x = LOWORD(lParam);
\r
7666 pt.y = HIWORD(lParam);
\r
7667 MenuPopup(hwnd, pt, hmenu, -1);
\r
7671 switch (LOWORD(wParam)) {
\r
7672 case IDM_QuickPaste:
\r
7674 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7675 if (sel.cpMin == sel.cpMax) {
\r
7676 MessageBeep(MB_ICONEXCLAMATION);
\r
7679 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7680 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7681 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7686 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7689 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7692 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7696 int i = LOWORD(wParam) - IDM_CommandX;
\r
7697 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7698 icsTextMenuEntry[i].command != NULL) {
\r
7699 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7700 icsTextMenuEntry[i].getname,
\r
7701 icsTextMenuEntry[i].immediate);
\r
7709 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7712 WNDPROC consoleInputWindowProc;
\r
7715 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7717 char buf[MSG_SIZ];
\r
7719 static BOOL sendNextChar = FALSE;
\r
7720 static BOOL quoteNextChar = FALSE;
\r
7721 InputSource *is = consoleInputSource;
\r
7725 switch (message) {
\r
7727 if (!appData.localLineEditing || sendNextChar) {
\r
7728 is->buf[0] = (CHAR) wParam;
\r
7730 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7731 sendNextChar = FALSE;
\r
7734 if (quoteNextChar) {
\r
7735 buf[0] = (char) wParam;
\r
7736 buf[1] = NULLCHAR;
\r
7737 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7738 quoteNextChar = FALSE;
\r
7742 case '\r': /* Enter key */
\r
7743 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7744 if (consoleEcho) SaveInHistory(is->buf);
\r
7745 is->buf[is->count++] = '\n';
\r
7746 is->buf[is->count] = NULLCHAR;
\r
7747 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7748 if (consoleEcho) {
\r
7749 ConsoleOutput(is->buf, is->count, TRUE);
\r
7750 } else if (appData.localLineEditing) {
\r
7751 ConsoleOutput("\n", 1, TRUE);
\r
7754 case '\033': /* Escape key */
\r
7755 SetWindowText(hwnd, "");
\r
7756 cf.cbSize = sizeof(CHARFORMAT);
\r
7757 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7758 if (consoleEcho) {
\r
7759 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7761 cf.crTextColor = COLOR_ECHOOFF;
\r
7763 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7764 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7766 case '\t': /* Tab key */
\r
7767 if (GetKeyState(VK_SHIFT) < 0) {
\r
7769 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7772 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7773 if (buttonDesc[0].hwnd) {
\r
7774 SetFocus(buttonDesc[0].hwnd);
\r
7776 SetFocus(hwndMain);
\r
7780 case '\023': /* Ctrl+S */
\r
7781 sendNextChar = TRUE;
\r
7783 case '\021': /* Ctrl+Q */
\r
7784 quoteNextChar = TRUE;
\r
7793 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7794 p = PrevInHistory(buf);
\r
7796 SetWindowText(hwnd, p);
\r
7797 sel.cpMin = 999999;
\r
7798 sel.cpMax = 999999;
\r
7799 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7804 p = NextInHistory();
\r
7806 SetWindowText(hwnd, p);
\r
7807 sel.cpMin = 999999;
\r
7808 sel.cpMax = 999999;
\r
7809 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7815 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7819 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7823 case WM_MBUTTONDOWN:
\r
7824 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7825 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7827 case WM_RBUTTONUP:
\r
7828 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7829 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7830 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7834 hmenu = LoadMenu(hInst, "InputMenu");
\r
7835 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7836 if (sel.cpMin == sel.cpMax) {
\r
7837 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7838 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7840 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7841 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7843 pt.x = LOWORD(lParam);
\r
7844 pt.y = HIWORD(lParam);
\r
7845 MenuPopup(hwnd, pt, hmenu, -1);
\r
7849 switch (LOWORD(wParam)) {
\r
7851 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7853 case IDM_SelectAll:
\r
7855 sel.cpMax = -1; /*999999?*/
\r
7856 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7859 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7862 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7865 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7870 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7873 #define CO_MAX 100000
\r
7874 #define CO_TRIM 1000
\r
7877 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7879 static SnapData sd;
\r
7880 static HWND hText, hInput, hFocus;
\r
7881 InputSource *is = consoleInputSource;
\r
7883 static int sizeX, sizeY;
\r
7884 int newSizeX, newSizeY;
\r
7887 switch (message) {
\r
7888 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7889 hwndConsole = hDlg;
\r
7890 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7891 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7893 consoleTextWindowProc = (WNDPROC)
\r
7894 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7895 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7896 consoleInputWindowProc = (WNDPROC)
\r
7897 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7898 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7899 Colorize(ColorNormal, TRUE);
\r
7900 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7901 ChangedConsoleFont();
\r
7902 GetClientRect(hDlg, &rect);
\r
7903 sizeX = rect.right;
\r
7904 sizeY = rect.bottom;
\r
7905 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7906 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7907 WINDOWPLACEMENT wp;
\r
7908 EnsureOnScreen(&consoleX, &consoleY);
\r
7909 wp.length = sizeof(WINDOWPLACEMENT);
\r
7911 wp.showCmd = SW_SHOW;
\r
7912 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7913 wp.rcNormalPosition.left = consoleX;
\r
7914 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7915 wp.rcNormalPosition.top = consoleY;
\r
7916 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7917 SetWindowPlacement(hDlg, &wp);
\r
7931 if (IsIconic(hDlg)) break;
\r
7932 newSizeX = LOWORD(lParam);
\r
7933 newSizeY = HIWORD(lParam);
\r
7934 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7935 RECT rectText, rectInput;
\r
7937 int newTextHeight, newTextWidth;
\r
7938 GetWindowRect(hText, &rectText);
\r
7939 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7940 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7941 if (newTextHeight < 0) {
\r
7942 newSizeY += -newTextHeight;
\r
7943 newTextHeight = 0;
\r
7945 SetWindowPos(hText, NULL, 0, 0,
\r
7946 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7947 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7948 pt.x = rectInput.left;
\r
7949 pt.y = rectInput.top + newSizeY - sizeY;
\r
7950 ScreenToClient(hDlg, &pt);
\r
7951 SetWindowPos(hInput, NULL,
\r
7952 pt.x, pt.y, /* needs client coords */
\r
7953 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7954 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7960 case WM_GETMINMAXINFO:
\r
7961 /* Prevent resizing window too small */
\r
7962 mmi = (MINMAXINFO *) lParam;
\r
7963 mmi->ptMinTrackSize.x = 100;
\r
7964 mmi->ptMinTrackSize.y = 100;
\r
7967 /* [AS] Snapping */
\r
7968 case WM_ENTERSIZEMOVE:
\r
7969 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7972 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7975 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7977 case WM_EXITSIZEMOVE:
\r
7978 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7981 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7989 if (hwndConsole) return;
\r
7990 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7991 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7996 ConsoleOutput(char* data, int length, int forceVisible)
\r
8001 char buf[CO_MAX+1];
\r
8004 static int delayLF = 0;
\r
8005 CHARRANGE savesel, sel;
\r
8007 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8015 while (length--) {
\r
8023 } else if (*p == '\007') {
\r
8024 MyPlaySound(&sounds[(int)SoundBell]);
\r
8031 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8032 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8033 /* Save current selection */
\r
8034 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8035 exlen = GetWindowTextLength(hText);
\r
8036 /* Find out whether current end of text is visible */
\r
8037 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8038 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8039 /* Trim existing text if it's too long */
\r
8040 if (exlen + (q - buf) > CO_MAX) {
\r
8041 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8044 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8045 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8047 savesel.cpMin -= trim;
\r
8048 savesel.cpMax -= trim;
\r
8049 if (exlen < 0) exlen = 0;
\r
8050 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8051 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8053 /* Append the new text */
\r
8054 sel.cpMin = exlen;
\r
8055 sel.cpMax = exlen;
\r
8056 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8057 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8058 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8059 if (forceVisible || exlen == 0 ||
\r
8060 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8061 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8062 /* Scroll to make new end of text visible if old end of text
\r
8063 was visible or new text is an echo of user typein */
\r
8064 sel.cpMin = 9999999;
\r
8065 sel.cpMax = 9999999;
\r
8066 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8067 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8068 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8069 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8071 if (savesel.cpMax == exlen || forceVisible) {
\r
8072 /* Move insert point to new end of text if it was at the old
\r
8073 end of text or if the new text is an echo of user typein */
\r
8074 sel.cpMin = 9999999;
\r
8075 sel.cpMax = 9999999;
\r
8076 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8078 /* Restore previous selection */
\r
8079 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8081 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8088 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8092 COLORREF oldFg, oldBg;
\r
8096 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8098 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8099 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8100 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8103 rect.right = x + squareSize;
\r
8105 rect.bottom = y + squareSize;
\r
8108 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8109 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8110 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8111 &rect, str, strlen(str), NULL);
\r
8113 (void) SetTextColor(hdc, oldFg);
\r
8114 (void) SetBkColor(hdc, oldBg);
\r
8115 (void) SelectObject(hdc, oldFont);
\r
8119 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8120 RECT *rect, char *color, char *flagFell)
\r
8124 COLORREF oldFg, oldBg;
\r
8127 if (appData.clockMode) {
\r
8129 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8131 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8138 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8139 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8141 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8142 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8144 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8146 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8147 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8148 rect, str, strlen(str), NULL);
\r
8150 (void) SetTextColor(hdc, oldFg);
\r
8151 (void) SetBkColor(hdc, oldBg);
\r
8152 (void) SelectObject(hdc, oldFont);
\r
8157 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8163 if( count <= 0 ) {
\r
8164 if (appData.debugMode) {
\r
8165 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8168 return ERROR_INVALID_USER_BUFFER;
\r
8171 ResetEvent(ovl->hEvent);
\r
8172 ovl->Offset = ovl->OffsetHigh = 0;
\r
8173 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8177 err = GetLastError();
\r
8178 if (err == ERROR_IO_PENDING) {
\r
8179 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8183 err = GetLastError();
\r
8190 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8195 ResetEvent(ovl->hEvent);
\r
8196 ovl->Offset = ovl->OffsetHigh = 0;
\r
8197 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8201 err = GetLastError();
\r
8202 if (err == ERROR_IO_PENDING) {
\r
8203 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8207 err = GetLastError();
\r
8213 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8214 void CheckForInputBufferFull( InputSource * is )
\r
8216 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8217 /* Look for end of line */
\r
8218 char * p = is->buf;
\r
8220 while( p < is->next && *p != '\n' ) {
\r
8224 if( p >= is->next ) {
\r
8225 if (appData.debugMode) {
\r
8226 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8229 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8230 is->count = (DWORD) -1;
\r
8231 is->next = is->buf;
\r
8237 InputThread(LPVOID arg)
\r
8242 is = (InputSource *) arg;
\r
8243 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8244 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8245 while (is->hThread != NULL) {
\r
8246 is->error = DoReadFile(is->hFile, is->next,
\r
8247 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8248 &is->count, &ovl);
\r
8249 if (is->error == NO_ERROR) {
\r
8250 is->next += is->count;
\r
8252 if (is->error == ERROR_BROKEN_PIPE) {
\r
8253 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8256 is->count = (DWORD) -1;
\r
8257 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8262 CheckForInputBufferFull( is );
\r
8264 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8266 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8268 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8271 CloseHandle(ovl.hEvent);
\r
8272 CloseHandle(is->hFile);
\r
8274 if (appData.debugMode) {
\r
8275 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8282 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8284 NonOvlInputThread(LPVOID arg)
\r
8291 is = (InputSource *) arg;
\r
8292 while (is->hThread != NULL) {
\r
8293 is->error = ReadFile(is->hFile, is->next,
\r
8294 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8295 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8296 if (is->error == NO_ERROR) {
\r
8297 /* Change CRLF to LF */
\r
8298 if (is->next > is->buf) {
\r
8300 i = is->count + 1;
\r
8308 if (prev == '\r' && *p == '\n') {
\r
8320 if (is->error == ERROR_BROKEN_PIPE) {
\r
8321 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8324 is->count = (DWORD) -1;
\r
8328 CheckForInputBufferFull( is );
\r
8330 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8332 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8334 if (is->count < 0) break; /* Quit on error */
\r
8336 CloseHandle(is->hFile);
\r
8341 SocketInputThread(LPVOID arg)
\r
8345 is = (InputSource *) arg;
\r
8346 while (is->hThread != NULL) {
\r
8347 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8348 if ((int)is->count == SOCKET_ERROR) {
\r
8349 is->count = (DWORD) -1;
\r
8350 is->error = WSAGetLastError();
\r
8352 is->error = NO_ERROR;
\r
8353 is->next += is->count;
\r
8354 if (is->count == 0 && is->second == is) {
\r
8355 /* End of file on stderr; quit with no message */
\r
8359 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8361 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8363 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8369 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8373 is = (InputSource *) lParam;
\r
8374 if (is->lineByLine) {
\r
8375 /* Feed in lines one by one */
\r
8376 char *p = is->buf;
\r
8378 while (q < is->next) {
\r
8379 if (*q++ == '\n') {
\r
8380 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8385 /* Move any partial line to the start of the buffer */
\r
8387 while (p < is->next) {
\r
8392 if (is->error != NO_ERROR || is->count == 0) {
\r
8393 /* Notify backend of the error. Note: If there was a partial
\r
8394 line at the end, it is not flushed through. */
\r
8395 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8398 /* Feed in the whole chunk of input at once */
\r
8399 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8400 is->next = is->buf;
\r
8404 /*---------------------------------------------------------------------------*\
\r
8406 * Menu enables. Used when setting various modes.
\r
8408 \*---------------------------------------------------------------------------*/
\r
8416 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8418 while (enab->item > 0) {
\r
8419 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8424 Enables gnuEnables[] = {
\r
8425 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8426 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8427 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8428 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8429 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8430 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8431 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8432 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8433 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8434 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8438 Enables icsEnables[] = {
\r
8439 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8440 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8441 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8442 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8443 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8444 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8445 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8446 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8447 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8448 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8449 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8450 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8455 Enables zippyEnables[] = {
\r
8456 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8457 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8458 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8463 Enables ncpEnables[] = {
\r
8464 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8465 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8466 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8467 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8468 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8469 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8470 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8471 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8472 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8473 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8474 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8475 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8476 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8477 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8478 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8482 Enables trainingOnEnables[] = {
\r
8483 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8484 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8485 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8486 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8487 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8488 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8489 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8490 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8494 Enables trainingOffEnables[] = {
\r
8495 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8496 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8497 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8498 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8499 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8500 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8501 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8502 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8506 /* These modify either ncpEnables or gnuEnables */
\r
8507 Enables cmailEnables[] = {
\r
8508 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8509 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8510 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8511 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8513 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8518 Enables machineThinkingEnables[] = {
\r
8519 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8520 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8521 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8522 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8523 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8532 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8533 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8537 Enables userThinkingEnables[] = {
\r
8538 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8539 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8540 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8541 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8542 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8543 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8544 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8545 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8546 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8547 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8548 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8549 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8550 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8551 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8552 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8556 /*---------------------------------------------------------------------------*\
\r
8558 * Front-end interface functions exported by XBoard.
\r
8559 * Functions appear in same order as prototypes in frontend.h.
\r
8561 \*---------------------------------------------------------------------------*/
\r
8565 static UINT prevChecked = 0;
\r
8566 static int prevPausing = 0;
\r
8569 if (pausing != prevPausing) {
\r
8570 prevPausing = pausing;
\r
8571 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8572 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8573 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8576 switch (gameMode) {
\r
8577 case BeginningOfGame:
\r
8578 if (appData.icsActive)
\r
8579 nowChecked = IDM_IcsClient;
\r
8580 else if (appData.noChessProgram)
\r
8581 nowChecked = IDM_EditGame;
\r
8583 nowChecked = IDM_MachineBlack;
\r
8585 case MachinePlaysBlack:
\r
8586 nowChecked = IDM_MachineBlack;
\r
8588 case MachinePlaysWhite:
\r
8589 nowChecked = IDM_MachineWhite;
\r
8591 case TwoMachinesPlay:
\r
8592 nowChecked = IDM_TwoMachines;
\r
8595 nowChecked = IDM_AnalysisMode;
\r
8598 nowChecked = IDM_AnalyzeFile;
\r
8601 nowChecked = IDM_EditGame;
\r
8603 case PlayFromGameFile:
\r
8604 nowChecked = IDM_LoadGame;
\r
8606 case EditPosition:
\r
8607 nowChecked = IDM_EditPosition;
\r
8610 nowChecked = IDM_Training;
\r
8612 case IcsPlayingWhite:
\r
8613 case IcsPlayingBlack:
\r
8614 case IcsObserving:
\r
8616 nowChecked = IDM_IcsClient;
\r
8623 if (prevChecked != 0)
\r
8624 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8625 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8626 if (nowChecked != 0)
\r
8627 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8628 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8630 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8631 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8632 MF_BYCOMMAND|MF_ENABLED);
\r
8634 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8635 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8638 prevChecked = nowChecked;
\r
8644 HMENU hmenu = GetMenu(hwndMain);
\r
8645 SetMenuEnables(hmenu, icsEnables);
\r
8646 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8647 MF_BYPOSITION|MF_ENABLED);
\r
8649 if (appData.zippyPlay) {
\r
8650 SetMenuEnables(hmenu, zippyEnables);
\r
8658 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8664 HMENU hmenu = GetMenu(hwndMain);
\r
8665 SetMenuEnables(hmenu, ncpEnables);
\r
8666 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8667 MF_BYPOSITION|MF_GRAYED);
\r
8668 DrawMenuBar(hwndMain);
\r
8674 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8678 SetTrainingModeOn()
\r
8681 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8682 for (i = 0; i < N_BUTTONS; i++) {
\r
8683 if (buttonDesc[i].hwnd != NULL)
\r
8684 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8689 VOID SetTrainingModeOff()
\r
8692 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8693 for (i = 0; i < N_BUTTONS; i++) {
\r
8694 if (buttonDesc[i].hwnd != NULL)
\r
8695 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8701 SetUserThinkingEnables()
\r
8703 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8707 SetMachineThinkingEnables()
\r
8709 HMENU hMenu = GetMenu(hwndMain);
\r
8710 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8712 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8714 if (gameMode == MachinePlaysBlack) {
\r
8715 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8716 } else if (gameMode == MachinePlaysWhite) {
\r
8717 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8718 } else if (gameMode == TwoMachinesPlay) {
\r
8719 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8725 DisplayTitle(char *str)
\r
8727 char title[MSG_SIZ], *host;
\r
8728 if (str[0] != NULLCHAR) {
\r
8729 strcpy(title, str);
\r
8730 } else if (appData.icsActive) {
\r
8731 if (appData.icsCommPort[0] != NULLCHAR)
\r
8734 host = appData.icsHost;
\r
8735 sprintf(title, "%s: %s", szTitle, host);
\r
8736 } else if (appData.noChessProgram) {
\r
8737 strcpy(title, szTitle);
\r
8739 strcpy(title, szTitle);
\r
8740 strcat(title, ": ");
\r
8741 strcat(title, first.tidy);
\r
8743 SetWindowText(hwndMain, title);
\r
8748 DisplayMessage(char *str1, char *str2)
\r
8752 int remain = MESSAGE_TEXT_MAX - 1;
\r
8755 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8756 messageText[0] = NULLCHAR;
\r
8758 len = strlen(str1);
\r
8759 if (len > remain) len = remain;
\r
8760 strncpy(messageText, str1, len);
\r
8761 messageText[len] = NULLCHAR;
\r
8764 if (*str2 && remain >= 2) {
\r
8766 strcat(messageText, " ");
\r
8769 len = strlen(str2);
\r
8770 if (len > remain) len = remain;
\r
8771 strncat(messageText, str2, len);
\r
8773 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8775 if (IsIconic(hwndMain)) return;
\r
8776 hdc = GetDC(hwndMain);
\r
8777 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8778 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8779 &messageRect, messageText, strlen(messageText), NULL);
\r
8780 (void) SelectObject(hdc, oldFont);
\r
8781 (void) ReleaseDC(hwndMain, hdc);
\r
8785 DisplayError(char *str, int error)
\r
8787 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8793 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8794 NULL, error, LANG_NEUTRAL,
\r
8795 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8797 sprintf(buf, "%s:\n%s", str, buf2);
\r
8799 ErrorMap *em = errmap;
\r
8800 while (em->err != 0 && em->err != error) em++;
\r
8801 if (em->err != 0) {
\r
8802 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8804 sprintf(buf, "%s:\nError code %d", str, error);
\r
8809 ErrorPopUp("Error", buf);
\r
8814 DisplayMoveError(char *str)
\r
8816 fromX = fromY = -1;
\r
8817 ClearHighlights();
\r
8818 DrawPosition(FALSE, NULL);
\r
8819 if (appData.popupMoveErrors) {
\r
8820 ErrorPopUp("Error", str);
\r
8822 DisplayMessage(str, "");
\r
8823 moveErrorMessageUp = TRUE;
\r
8828 DisplayFatalError(char *str, int error, int exitStatus)
\r
8830 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8832 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8835 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8836 NULL, error, LANG_NEUTRAL,
\r
8837 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8839 sprintf(buf, "%s:\n%s", str, buf2);
\r
8841 ErrorMap *em = errmap;
\r
8842 while (em->err != 0 && em->err != error) em++;
\r
8843 if (em->err != 0) {
\r
8844 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8846 sprintf(buf, "%s:\nError code %d", str, error);
\r
8851 if (appData.debugMode) {
\r
8852 fprintf(debugFP, "%s: %s\n", label, str);
\r
8854 if (appData.popupExitMessage) {
\r
8855 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8856 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8858 ExitEvent(exitStatus);
\r
8863 DisplayInformation(char *str)
\r
8865 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8870 DisplayNote(char *str)
\r
8872 ErrorPopUp("Note", str);
\r
8877 char *title, *question, *replyPrefix;
\r
8882 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8884 static QuestionParams *qp;
\r
8885 char reply[MSG_SIZ];
\r
8888 switch (message) {
\r
8889 case WM_INITDIALOG:
\r
8890 qp = (QuestionParams *) lParam;
\r
8891 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8892 SetWindowText(hDlg, qp->title);
\r
8893 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8894 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8898 switch (LOWORD(wParam)) {
\r
8900 strcpy(reply, qp->replyPrefix);
\r
8901 if (*reply) strcat(reply, " ");
\r
8902 len = strlen(reply);
\r
8903 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8904 strcat(reply, "\n");
\r
8905 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8906 EndDialog(hDlg, TRUE);
\r
8907 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8910 EndDialog(hDlg, FALSE);
\r
8921 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8923 QuestionParams qp;
\r
8927 qp.question = question;
\r
8928 qp.replyPrefix = replyPrefix;
\r
8930 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8931 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8932 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8933 FreeProcInstance(lpProc);
\r
8936 /* [AS] Pick FRC position */
\r
8937 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8939 static int * lpIndexFRC;
\r
8945 case WM_INITDIALOG:
\r
8946 lpIndexFRC = (int *) lParam;
\r
8948 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8950 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8951 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8952 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8953 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8958 switch( LOWORD(wParam) ) {
\r
8960 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8961 EndDialog( hDlg, 0 );
\r
8962 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8965 EndDialog( hDlg, 1 );
\r
8967 case IDC_NFG_Edit:
\r
8968 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8969 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8971 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8974 case IDC_NFG_Random:
\r
8975 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8976 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8989 int index = appData.defaultFrcPosition;
\r
8990 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8992 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8994 if( result == 0 ) {
\r
8995 appData.defaultFrcPosition = index;
\r
9001 /* [AS] Game list options */
\r
9007 static GLT_Item GLT_ItemInfo[] = {
\r
9008 { GLT_EVENT, "Event" },
\r
9009 { GLT_SITE, "Site" },
\r
9010 { GLT_DATE, "Date" },
\r
9011 { GLT_ROUND, "Round" },
\r
9012 { GLT_PLAYERS, "Players" },
\r
9013 { GLT_RESULT, "Result" },
\r
9014 { GLT_WHITE_ELO, "White Rating" },
\r
9015 { GLT_BLACK_ELO, "Black Rating" },
\r
9016 { GLT_TIME_CONTROL,"Time Control" },
\r
9017 { GLT_VARIANT, "Variant" },
\r
9018 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9022 const char * GLT_FindItem( char id )
\r
9024 const char * result = 0;
\r
9026 GLT_Item * list = GLT_ItemInfo;
\r
9028 while( list->id != 0 ) {
\r
9029 if( list->id == id ) {
\r
9030 result = list->name;
\r
9040 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9042 const char * name = GLT_FindItem( id );
\r
9045 if( index >= 0 ) {
\r
9046 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9049 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9054 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9058 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9061 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9065 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9067 pc = GLT_ALL_TAGS;
\r
9070 if( strchr( tags, *pc ) == 0 ) {
\r
9071 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9076 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9079 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9081 char result = '\0';
\r
9084 GLT_Item * list = GLT_ItemInfo;
\r
9086 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9087 while( list->id != 0 ) {
\r
9088 if( strcmp( list->name, name ) == 0 ) {
\r
9089 result = list->id;
\r
9100 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9102 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9103 int idx2 = idx1 + delta;
\r
9104 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9106 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9109 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9110 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9111 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9112 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9116 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9118 static char glt[64];
\r
9119 static char * lpUserGLT;
\r
9123 case WM_INITDIALOG:
\r
9124 lpUserGLT = (char *) lParam;
\r
9126 strcpy( glt, lpUserGLT );
\r
9128 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9130 /* Initialize list */
\r
9131 GLT_TagsToList( hDlg, glt );
\r
9133 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9138 switch( LOWORD(wParam) ) {
\r
9141 char * pc = lpUserGLT;
\r
9143 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9147 id = GLT_ListItemToTag( hDlg, idx );
\r
9151 } while( id != '\0' );
\r
9153 EndDialog( hDlg, 0 );
\r
9156 EndDialog( hDlg, 1 );
\r
9159 case IDC_GLT_Default:
\r
9160 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9161 GLT_TagsToList( hDlg, glt );
\r
9164 case IDC_GLT_Restore:
\r
9165 strcpy( glt, lpUserGLT );
\r
9166 GLT_TagsToList( hDlg, glt );
\r
9170 GLT_MoveSelection( hDlg, -1 );
\r
9173 case IDC_GLT_Down:
\r
9174 GLT_MoveSelection( hDlg, +1 );
\r
9184 int GameListOptions()
\r
9188 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9190 strcpy( glt, appData.gameListTags );
\r
9192 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9194 if( result == 0 ) {
\r
9195 /* [AS] Memory leak here! */
\r
9196 appData.gameListTags = strdup( glt );
\r
9204 DisplayIcsInteractionTitle(char *str)
\r
9206 char consoleTitle[MSG_SIZ];
\r
9208 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9209 SetWindowText(hwndConsole, consoleTitle);
\r
9213 DrawPosition(int fullRedraw, Board board)
\r
9215 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9222 fromX = fromY = -1;
\r
9223 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9224 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9225 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9226 dragInfo.lastpos = dragInfo.pos;
\r
9227 dragInfo.start.x = dragInfo.start.y = -1;
\r
9228 dragInfo.from = dragInfo.start;
\r
9230 DrawPosition(TRUE, NULL);
\r
9236 CommentPopUp(char *title, char *str)
\r
9238 HWND hwnd = GetActiveWindow();
\r
9239 EitherCommentPopUp(0, title, str, FALSE);
\r
9240 SetActiveWindow(hwnd);
\r
9244 CommentPopDown(void)
\r
9246 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9247 if (commentDialog) {
\r
9248 ShowWindow(commentDialog, SW_HIDE);
\r
9250 commentDialogUp = FALSE;
\r
9254 EditCommentPopUp(int index, char *title, char *str)
\r
9256 EitherCommentPopUp(index, title, str, TRUE);
\r
9263 MyPlaySound(&sounds[(int)SoundMove]);
\r
9266 VOID PlayIcsWinSound()
\r
9268 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9271 VOID PlayIcsLossSound()
\r
9273 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9276 VOID PlayIcsDrawSound()
\r
9278 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9281 VOID PlayIcsUnfinishedSound()
\r
9283 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9289 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9297 consoleEcho = TRUE;
\r
9298 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9299 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9300 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9309 consoleEcho = FALSE;
\r
9310 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9311 /* This works OK: set text and background both to the same color */
\r
9313 cf.crTextColor = COLOR_ECHOOFF;
\r
9314 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9315 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9318 /* No Raw()...? */
\r
9320 void Colorize(ColorClass cc, int continuation)
\r
9322 currentColorClass = cc;
\r
9323 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9324 consoleCF.crTextColor = textAttribs[cc].color;
\r
9325 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9326 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9332 static char buf[MSG_SIZ];
\r
9333 DWORD bufsiz = MSG_SIZ;
\r
9335 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9336 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9338 if (!GetUserName(buf, &bufsiz)) {
\r
9339 /*DisplayError("Error getting user name", GetLastError());*/
\r
9340 strcpy(buf, "User");
\r
9348 static char buf[MSG_SIZ];
\r
9349 DWORD bufsiz = MSG_SIZ;
\r
9351 if (!GetComputerName(buf, &bufsiz)) {
\r
9352 /*DisplayError("Error getting host name", GetLastError());*/
\r
9353 strcpy(buf, "Unknown");
\r
9360 ClockTimerRunning()
\r
9362 return clockTimerEvent != 0;
\r
9368 if (clockTimerEvent == 0) return FALSE;
\r
9369 KillTimer(hwndMain, clockTimerEvent);
\r
9370 clockTimerEvent = 0;
\r
9375 StartClockTimer(long millisec)
\r
9377 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9378 (UINT) millisec, NULL);
\r
9382 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9385 hdc = GetDC(hwndMain);
\r
9386 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9388 if (!IsIconic(hwndMain)) {
\r
9389 DisplayAClock(hdc, timeRemaining, highlight,
\r
9390 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9392 if (highlight && iconCurrent == iconBlack) {
\r
9393 iconCurrent = iconWhite;
\r
9394 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9395 if (IsIconic(hwndMain)) {
\r
9396 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9399 (void) ReleaseDC(hwndMain, hdc);
\r
9401 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9405 DisplayBlackClock(long timeRemaining, int highlight)
\r
9408 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9410 hdc = GetDC(hwndMain);
\r
9411 if (!IsIconic(hwndMain)) {
\r
9412 DisplayAClock(hdc, timeRemaining, highlight,
\r
9413 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9415 if (highlight && iconCurrent == iconWhite) {
\r
9416 iconCurrent = iconBlack;
\r
9417 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9418 if (IsIconic(hwndMain)) {
\r
9419 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9422 (void) ReleaseDC(hwndMain, hdc);
\r
9424 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9429 LoadGameTimerRunning()
\r
9431 return loadGameTimerEvent != 0;
\r
9435 StopLoadGameTimer()
\r
9437 if (loadGameTimerEvent == 0) return FALSE;
\r
9438 KillTimer(hwndMain, loadGameTimerEvent);
\r
9439 loadGameTimerEvent = 0;
\r
9444 StartLoadGameTimer(long millisec)
\r
9446 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9447 (UINT) millisec, NULL);
\r
9455 char fileTitle[MSG_SIZ];
\r
9457 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9458 f = OpenFileDialog(hwndMain, "a", defName,
\r
9459 appData.oldSaveStyle ? "gam" : "pgn",
\r
9461 "Save Game to File", NULL, fileTitle, NULL);
\r
9463 SaveGame(f, 0, "");
\r
9470 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9472 if (delayedTimerEvent != 0) {
\r
9473 if (appData.debugMode) {
\r
9474 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9476 KillTimer(hwndMain, delayedTimerEvent);
\r
9477 delayedTimerEvent = 0;
\r
9478 delayedTimerCallback();
\r
9480 delayedTimerCallback = cb;
\r
9481 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9482 (UINT) millisec, NULL);
\r
9485 DelayedEventCallback
\r
9488 if (delayedTimerEvent) {
\r
9489 return delayedTimerCallback;
\r
9496 CancelDelayedEvent()
\r
9498 if (delayedTimerEvent) {
\r
9499 KillTimer(hwndMain, delayedTimerEvent);
\r
9500 delayedTimerEvent = 0;
\r
9504 DWORD GetWin32Priority(int nice)
\r
9505 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9507 REALTIME_PRIORITY_CLASS 0x00000100
\r
9508 HIGH_PRIORITY_CLASS 0x00000080
\r
9509 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9510 NORMAL_PRIORITY_CLASS 0x00000020
\r
9511 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9512 IDLE_PRIORITY_CLASS 0x00000040
\r
9514 if (nice < -15) return 0x00000080;
\r
9515 if (nice < 0) return 0x00008000;
\r
9516 if (nice == 0) return 0x00000020;
\r
9517 if (nice < 15) return 0x00004000;
\r
9518 return 0x00000040;
\r
9521 /* Start a child process running the given program.
\r
9522 The process's standard output can be read from "from", and its
\r
9523 standard input can be written to "to".
\r
9524 Exit with fatal error if anything goes wrong.
\r
9525 Returns an opaque pointer that can be used to destroy the process
\r
9529 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9531 #define BUFSIZE 4096
\r
9533 HANDLE hChildStdinRd, hChildStdinWr,
\r
9534 hChildStdoutRd, hChildStdoutWr;
\r
9535 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9536 SECURITY_ATTRIBUTES saAttr;
\r
9538 PROCESS_INFORMATION piProcInfo;
\r
9539 STARTUPINFO siStartInfo;
\r
9541 char buf[MSG_SIZ];
\r
9544 if (appData.debugMode) {
\r
9545 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9550 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9551 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9552 saAttr.bInheritHandle = TRUE;
\r
9553 saAttr.lpSecurityDescriptor = NULL;
\r
9556 * The steps for redirecting child's STDOUT:
\r
9557 * 1. Create anonymous pipe to be STDOUT for child.
\r
9558 * 2. Create a noninheritable duplicate of read handle,
\r
9559 * and close the inheritable read handle.
\r
9562 /* Create a pipe for the child's STDOUT. */
\r
9563 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9564 return GetLastError();
\r
9567 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9568 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9569 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9570 FALSE, /* not inherited */
\r
9571 DUPLICATE_SAME_ACCESS);
\r
9573 return GetLastError();
\r
9575 CloseHandle(hChildStdoutRd);
\r
9578 * The steps for redirecting child's STDIN:
\r
9579 * 1. Create anonymous pipe to be STDIN for child.
\r
9580 * 2. Create a noninheritable duplicate of write handle,
\r
9581 * and close the inheritable write handle.
\r
9584 /* Create a pipe for the child's STDIN. */
\r
9585 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9586 return GetLastError();
\r
9589 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9590 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9591 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9592 FALSE, /* not inherited */
\r
9593 DUPLICATE_SAME_ACCESS);
\r
9595 return GetLastError();
\r
9597 CloseHandle(hChildStdinWr);
\r
9599 /* Arrange to (1) look in dir for the child .exe file, and
\r
9600 * (2) have dir be the child's working directory. Interpret
\r
9601 * dir relative to the directory WinBoard loaded from. */
\r
9602 GetCurrentDirectory(MSG_SIZ, buf);
\r
9603 SetCurrentDirectory(installDir);
\r
9604 SetCurrentDirectory(dir);
\r
9606 /* Now create the child process. */
\r
9608 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9609 siStartInfo.lpReserved = NULL;
\r
9610 siStartInfo.lpDesktop = NULL;
\r
9611 siStartInfo.lpTitle = NULL;
\r
9612 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9613 siStartInfo.cbReserved2 = 0;
\r
9614 siStartInfo.lpReserved2 = NULL;
\r
9615 siStartInfo.hStdInput = hChildStdinRd;
\r
9616 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9617 siStartInfo.hStdError = hChildStdoutWr;
\r
9619 fSuccess = CreateProcess(NULL,
\r
9620 cmdLine, /* command line */
\r
9621 NULL, /* process security attributes */
\r
9622 NULL, /* primary thread security attrs */
\r
9623 TRUE, /* handles are inherited */
\r
9624 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9625 NULL, /* use parent's environment */
\r
9627 &siStartInfo, /* STARTUPINFO pointer */
\r
9628 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9630 err = GetLastError();
\r
9631 SetCurrentDirectory(buf); /* return to prev directory */
\r
9636 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9637 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9638 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9641 /* Close the handles we don't need in the parent */
\r
9642 CloseHandle(piProcInfo.hThread);
\r
9643 CloseHandle(hChildStdinRd);
\r
9644 CloseHandle(hChildStdoutWr);
\r
9646 /* Prepare return value */
\r
9647 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9648 cp->kind = CPReal;
\r
9649 cp->hProcess = piProcInfo.hProcess;
\r
9650 cp->pid = piProcInfo.dwProcessId;
\r
9651 cp->hFrom = hChildStdoutRdDup;
\r
9652 cp->hTo = hChildStdinWrDup;
\r
9654 *pr = (void *) cp;
\r
9656 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9657 2000 where engines sometimes don't see the initial command(s)
\r
9658 from WinBoard and hang. I don't understand how that can happen,
\r
9659 but the Sleep is harmless, so I've put it in. Others have also
\r
9660 reported what may be the same problem, so hopefully this will fix
\r
9661 it for them too. */
\r
9669 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9671 ChildProc *cp; int result;
\r
9673 cp = (ChildProc *) pr;
\r
9674 if (cp == NULL) return;
\r
9676 switch (cp->kind) {
\r
9678 /* TerminateProcess is considered harmful, so... */
\r
9679 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9680 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9681 /* The following doesn't work because the chess program
\r
9682 doesn't "have the same console" as WinBoard. Maybe
\r
9683 we could arrange for this even though neither WinBoard
\r
9684 nor the chess program uses a console for stdio? */
\r
9685 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9687 /* [AS] Special termination modes for misbehaving programs... */
\r
9688 if( signal == 9 ) {
\r
9689 result = TerminateProcess( cp->hProcess, 0 );
\r
9691 if ( appData.debugMode) {
\r
9692 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9695 else if( signal == 10 ) {
\r
9696 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9698 if( dw != WAIT_OBJECT_0 ) {
\r
9699 result = TerminateProcess( cp->hProcess, 0 );
\r
9701 if ( appData.debugMode) {
\r
9702 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9708 CloseHandle(cp->hProcess);
\r
9712 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9716 closesocket(cp->sock);
\r
9721 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9722 closesocket(cp->sock);
\r
9723 closesocket(cp->sock2);
\r
9731 InterruptChildProcess(ProcRef pr)
\r
9735 cp = (ChildProc *) pr;
\r
9736 if (cp == NULL) return;
\r
9737 switch (cp->kind) {
\r
9739 /* The following doesn't work because the chess program
\r
9740 doesn't "have the same console" as WinBoard. Maybe
\r
9741 we could arrange for this even though neither WinBoard
\r
9742 nor the chess program uses a console for stdio */
\r
9743 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9748 /* Can't interrupt */
\r
9752 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9759 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9761 char cmdLine[MSG_SIZ];
\r
9763 if (port[0] == NULLCHAR) {
\r
9764 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9766 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9768 return StartChildProcess(cmdLine, "", pr);
\r
9772 /* Code to open TCP sockets */
\r
9775 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9780 struct sockaddr_in sa, mysa;
\r
9781 struct hostent FAR *hp;
\r
9782 unsigned short uport;
\r
9783 WORD wVersionRequested;
\r
9786 /* Initialize socket DLL */
\r
9787 wVersionRequested = MAKEWORD(1, 1);
\r
9788 err = WSAStartup(wVersionRequested, &wsaData);
\r
9789 if (err != 0) return err;
\r
9792 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9793 err = WSAGetLastError();
\r
9798 /* Bind local address using (mostly) don't-care values.
\r
9800 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9801 mysa.sin_family = AF_INET;
\r
9802 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9803 uport = (unsigned short) 0;
\r
9804 mysa.sin_port = htons(uport);
\r
9805 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9806 == SOCKET_ERROR) {
\r
9807 err = WSAGetLastError();
\r
9812 /* Resolve remote host name */
\r
9813 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9814 if (!(hp = gethostbyname(host))) {
\r
9815 unsigned int b0, b1, b2, b3;
\r
9817 err = WSAGetLastError();
\r
9819 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9820 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9821 hp->h_addrtype = AF_INET;
\r
9823 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9824 hp->h_addr_list[0] = (char *) malloc(4);
\r
9825 hp->h_addr_list[0][0] = (char) b0;
\r
9826 hp->h_addr_list[0][1] = (char) b1;
\r
9827 hp->h_addr_list[0][2] = (char) b2;
\r
9828 hp->h_addr_list[0][3] = (char) b3;
\r
9834 sa.sin_family = hp->h_addrtype;
\r
9835 uport = (unsigned short) atoi(port);
\r
9836 sa.sin_port = htons(uport);
\r
9837 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9839 /* Make connection */
\r
9840 if (connect(s, (struct sockaddr *) &sa,
\r
9841 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9842 err = WSAGetLastError();
\r
9847 /* Prepare return value */
\r
9848 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9849 cp->kind = CPSock;
\r
9851 *pr = (ProcRef *) cp;
\r
9857 OpenCommPort(char *name, ProcRef *pr)
\r
9862 char fullname[MSG_SIZ];
\r
9864 if (*name != '\\')
\r
9865 sprintf(fullname, "\\\\.\\%s", name);
\r
9867 strcpy(fullname, name);
\r
9869 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9870 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9871 if (h == (HANDLE) -1) {
\r
9872 return GetLastError();
\r
9876 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9878 /* Accumulate characters until a 100ms pause, then parse */
\r
9879 ct.ReadIntervalTimeout = 100;
\r
9880 ct.ReadTotalTimeoutMultiplier = 0;
\r
9881 ct.ReadTotalTimeoutConstant = 0;
\r
9882 ct.WriteTotalTimeoutMultiplier = 0;
\r
9883 ct.WriteTotalTimeoutConstant = 0;
\r
9884 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9886 /* Prepare return value */
\r
9887 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9888 cp->kind = CPComm;
\r
9891 *pr = (ProcRef *) cp;
\r
9897 OpenLoopback(ProcRef *pr)
\r
9899 DisplayFatalError("Not implemented", 0, 1);
\r
9905 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9910 struct sockaddr_in sa, mysa;
\r
9911 struct hostent FAR *hp;
\r
9912 unsigned short uport;
\r
9913 WORD wVersionRequested;
\r
9916 char stderrPortStr[MSG_SIZ];
\r
9918 /* Initialize socket DLL */
\r
9919 wVersionRequested = MAKEWORD(1, 1);
\r
9920 err = WSAStartup(wVersionRequested, &wsaData);
\r
9921 if (err != 0) return err;
\r
9923 /* Resolve remote host name */
\r
9924 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9925 if (!(hp = gethostbyname(host))) {
\r
9926 unsigned int b0, b1, b2, b3;
\r
9928 err = WSAGetLastError();
\r
9930 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9931 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9932 hp->h_addrtype = AF_INET;
\r
9934 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9935 hp->h_addr_list[0] = (char *) malloc(4);
\r
9936 hp->h_addr_list[0][0] = (char) b0;
\r
9937 hp->h_addr_list[0][1] = (char) b1;
\r
9938 hp->h_addr_list[0][2] = (char) b2;
\r
9939 hp->h_addr_list[0][3] = (char) b3;
\r
9945 sa.sin_family = hp->h_addrtype;
\r
9946 uport = (unsigned short) 514;
\r
9947 sa.sin_port = htons(uport);
\r
9948 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9950 /* Bind local socket to unused "privileged" port address
\r
9952 s = INVALID_SOCKET;
\r
9953 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9954 mysa.sin_family = AF_INET;
\r
9955 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9956 for (fromPort = 1023;; fromPort--) {
\r
9957 if (fromPort < 0) {
\r
9959 return WSAEADDRINUSE;
\r
9961 if (s == INVALID_SOCKET) {
\r
9962 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9963 err = WSAGetLastError();
\r
9968 uport = (unsigned short) fromPort;
\r
9969 mysa.sin_port = htons(uport);
\r
9970 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9971 == SOCKET_ERROR) {
\r
9972 err = WSAGetLastError();
\r
9973 if (err == WSAEADDRINUSE) continue;
\r
9977 if (connect(s, (struct sockaddr *) &sa,
\r
9978 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9979 err = WSAGetLastError();
\r
9980 if (err == WSAEADDRINUSE) {
\r
9991 /* Bind stderr local socket to unused "privileged" port address
\r
9993 s2 = INVALID_SOCKET;
\r
9994 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9995 mysa.sin_family = AF_INET;
\r
9996 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9997 for (fromPort = 1023;; fromPort--) {
\r
9998 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9999 if (fromPort < 0) {
\r
10000 (void) closesocket(s);
\r
10002 return WSAEADDRINUSE;
\r
10004 if (s2 == INVALID_SOCKET) {
\r
10005 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10006 err = WSAGetLastError();
\r
10012 uport = (unsigned short) fromPort;
\r
10013 mysa.sin_port = htons(uport);
\r
10014 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10015 == SOCKET_ERROR) {
\r
10016 err = WSAGetLastError();
\r
10017 if (err == WSAEADDRINUSE) continue;
\r
10018 (void) closesocket(s);
\r
10022 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10023 err = WSAGetLastError();
\r
10024 if (err == WSAEADDRINUSE) {
\r
10026 s2 = INVALID_SOCKET;
\r
10029 (void) closesocket(s);
\r
10030 (void) closesocket(s2);
\r
10036 prevStderrPort = fromPort; // remember port used
\r
10037 sprintf(stderrPortStr, "%d", fromPort);
\r
10039 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10040 err = WSAGetLastError();
\r
10041 (void) closesocket(s);
\r
10042 (void) closesocket(s2);
\r
10047 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10048 err = WSAGetLastError();
\r
10049 (void) closesocket(s);
\r
10050 (void) closesocket(s2);
\r
10054 if (*user == NULLCHAR) user = UserName();
\r
10055 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10056 err = WSAGetLastError();
\r
10057 (void) closesocket(s);
\r
10058 (void) closesocket(s2);
\r
10062 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10063 err = WSAGetLastError();
\r
10064 (void) closesocket(s);
\r
10065 (void) closesocket(s2);
\r
10070 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10071 err = WSAGetLastError();
\r
10072 (void) closesocket(s);
\r
10073 (void) closesocket(s2);
\r
10077 (void) closesocket(s2); /* Stop listening */
\r
10079 /* Prepare return value */
\r
10080 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10081 cp->kind = CPRcmd;
\r
10084 *pr = (ProcRef *) cp;
\r
10091 AddInputSource(ProcRef pr, int lineByLine,
\r
10092 InputCallback func, VOIDSTAR closure)
\r
10094 InputSource *is, *is2 = NULL;
\r
10095 ChildProc *cp = (ChildProc *) pr;
\r
10097 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10098 is->lineByLine = lineByLine;
\r
10100 is->closure = closure;
\r
10101 is->second = NULL;
\r
10102 is->next = is->buf;
\r
10103 if (pr == NoProc) {
\r
10104 is->kind = CPReal;
\r
10105 consoleInputSource = is;
\r
10107 is->kind = cp->kind;
\r
10109 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10110 we create all threads suspended so that the is->hThread variable can be
\r
10111 safely assigned, then let the threads start with ResumeThread.
\r
10113 switch (cp->kind) {
\r
10115 is->hFile = cp->hFrom;
\r
10116 cp->hFrom = NULL; /* now owned by InputThread */
\r
10118 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10119 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10123 is->hFile = cp->hFrom;
\r
10124 cp->hFrom = NULL; /* now owned by InputThread */
\r
10126 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10127 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10131 is->sock = cp->sock;
\r
10133 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10134 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10138 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10140 is->sock = cp->sock;
\r
10141 is->second = is2;
\r
10142 is2->sock = cp->sock2;
\r
10143 is2->second = is2;
\r
10145 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10146 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10148 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10149 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10153 if( is->hThread != NULL ) {
\r
10154 ResumeThread( is->hThread );
\r
10157 if( is2 != NULL && is2->hThread != NULL ) {
\r
10158 ResumeThread( is2->hThread );
\r
10162 return (InputSourceRef) is;
\r
10166 RemoveInputSource(InputSourceRef isr)
\r
10170 is = (InputSource *) isr;
\r
10171 is->hThread = NULL; /* tell thread to stop */
\r
10172 CloseHandle(is->hThread);
\r
10173 if (is->second != NULL) {
\r
10174 is->second->hThread = NULL;
\r
10175 CloseHandle(is->second->hThread);
\r
10181 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10184 int outCount = SOCKET_ERROR;
\r
10185 ChildProc *cp = (ChildProc *) pr;
\r
10186 static OVERLAPPED ovl;
\r
10188 if (pr == NoProc) {
\r
10189 ConsoleOutput(message, count, FALSE);
\r
10193 if (ovl.hEvent == NULL) {
\r
10194 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10196 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10198 switch (cp->kind) {
\r
10201 outCount = send(cp->sock, message, count, 0);
\r
10202 if (outCount == SOCKET_ERROR) {
\r
10203 *outError = WSAGetLastError();
\r
10205 *outError = NO_ERROR;
\r
10210 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10211 &dOutCount, NULL)) {
\r
10212 *outError = NO_ERROR;
\r
10213 outCount = (int) dOutCount;
\r
10215 *outError = GetLastError();
\r
10220 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10221 &dOutCount, &ovl);
\r
10222 if (*outError == NO_ERROR) {
\r
10223 outCount = (int) dOutCount;
\r
10231 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10234 /* Ignore delay, not implemented for WinBoard */
\r
10235 return OutputToProcess(pr, message, count, outError);
\r
10240 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10241 char *buf, int count, int error)
\r
10243 DisplayFatalError("Not implemented", 0, 1);
\r
10246 /* see wgamelist.c for Game List functions */
\r
10247 /* see wedittags.c for Edit Tags functions */
\r
10254 char buf[MSG_SIZ];
\r
10257 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10258 f = fopen(buf, "r");
\r
10260 ProcessICSInitScript(f);
\r
10268 StartAnalysisClock()
\r
10270 if (analysisTimerEvent) return;
\r
10271 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10272 (UINT) 2000, NULL);
\r
10276 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10278 static HANDLE hwndText;
\r
10280 static int sizeX, sizeY;
\r
10281 int newSizeX, newSizeY, flags;
\r
10284 switch (message) {
\r
10285 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10286 /* Initialize the dialog items */
\r
10287 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10288 SetWindowText(hDlg, analysisTitle);
\r
10289 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10290 /* Size and position the dialog */
\r
10291 if (!analysisDialog) {
\r
10292 analysisDialog = hDlg;
\r
10293 flags = SWP_NOZORDER;
\r
10294 GetClientRect(hDlg, &rect);
\r
10295 sizeX = rect.right;
\r
10296 sizeY = rect.bottom;
\r
10297 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10298 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10299 WINDOWPLACEMENT wp;
\r
10300 EnsureOnScreen(&analysisX, &analysisY);
\r
10301 wp.length = sizeof(WINDOWPLACEMENT);
\r
10303 wp.showCmd = SW_SHOW;
\r
10304 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10305 wp.rcNormalPosition.left = analysisX;
\r
10306 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10307 wp.rcNormalPosition.top = analysisY;
\r
10308 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10309 SetWindowPlacement(hDlg, &wp);
\r
10311 GetClientRect(hDlg, &rect);
\r
10312 newSizeX = rect.right;
\r
10313 newSizeY = rect.bottom;
\r
10314 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10315 newSizeX, newSizeY);
\r
10316 sizeX = newSizeX;
\r
10317 sizeY = newSizeY;
\r
10322 case WM_COMMAND: /* message: received a command */
\r
10323 switch (LOWORD(wParam)) {
\r
10333 newSizeX = LOWORD(lParam);
\r
10334 newSizeY = HIWORD(lParam);
\r
10335 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10336 sizeX = newSizeX;
\r
10337 sizeY = newSizeY;
\r
10340 case WM_GETMINMAXINFO:
\r
10341 /* Prevent resizing window too small */
\r
10342 mmi = (MINMAXINFO *) lParam;
\r
10343 mmi->ptMinTrackSize.x = 100;
\r
10344 mmi->ptMinTrackSize.y = 100;
\r
10351 AnalysisPopUp(char* title, char* str)
\r
10357 EngineOutputPopUp();
\r
10360 if (str == NULL) str = "";
\r
10361 p = (char *) malloc(2 * strlen(str) + 2);
\r
10364 if (*str == '\n') *q++ = '\r';
\r
10368 if (analysisText != NULL) free(analysisText);
\r
10369 analysisText = p;
\r
10371 if (analysisDialog) {
\r
10372 SetWindowText(analysisDialog, title);
\r
10373 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10374 ShowWindow(analysisDialog, SW_SHOW);
\r
10376 analysisTitle = title;
\r
10377 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10378 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10379 hwndMain, (DLGPROC)lpProc);
\r
10380 FreeProcInstance(lpProc);
\r
10382 analysisDialogUp = TRUE;
\r
10386 AnalysisPopDown()
\r
10388 if (analysisDialog) {
\r
10389 ShowWindow(analysisDialog, SW_HIDE);
\r
10391 analysisDialogUp = FALSE;
\r
10396 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10398 highlightInfo.sq[0].x = fromX;
\r
10399 highlightInfo.sq[0].y = fromY;
\r
10400 highlightInfo.sq[1].x = toX;
\r
10401 highlightInfo.sq[1].y = toY;
\r
10405 ClearHighlights()
\r
10407 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10408 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10412 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10414 premoveHighlightInfo.sq[0].x = fromX;
\r
10415 premoveHighlightInfo.sq[0].y = fromY;
\r
10416 premoveHighlightInfo.sq[1].x = toX;
\r
10417 premoveHighlightInfo.sq[1].y = toY;
\r
10421 ClearPremoveHighlights()
\r
10423 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10424 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10428 ShutDownFrontEnd()
\r
10430 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10431 DeleteClipboardTempFiles();
\r
10437 if (IsIconic(hwndMain))
\r
10438 ShowWindow(hwndMain, SW_RESTORE);
\r
10440 SetActiveWindow(hwndMain);
\r
10444 * Prototypes for animation support routines
\r
10446 static void ScreenSquare(int column, int row, POINT * pt);
\r
10447 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10448 POINT frames[], int * nFrames);
\r
10451 #define kFactor 4
\r
10454 AnimateMove(board, fromX, fromY, toX, toY)
\r
10461 ChessSquare piece;
\r
10462 POINT start, finish, mid;
\r
10463 POINT frames[kFactor * 2 + 1];
\r
10466 if (!appData.animate) return;
\r
10467 if (doingSizing) return;
\r
10468 if (fromY < 0 || fromX < 0) return;
\r
10469 piece = board[fromY][fromX];
\r
10470 if (piece >= EmptySquare) return;
\r
10472 ScreenSquare(fromX, fromY, &start);
\r
10473 ScreenSquare(toX, toY, &finish);
\r
10475 /* All pieces except knights move in straight line */
\r
10476 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10477 mid.x = start.x + (finish.x - start.x) / 2;
\r
10478 mid.y = start.y + (finish.y - start.y) / 2;
\r
10480 /* Knight: make diagonal movement then straight */
\r
10481 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10482 mid.x = start.x + (finish.x - start.x) / 2;
\r
10483 mid.y = finish.y;
\r
10485 mid.x = finish.x;
\r
10486 mid.y = start.y + (finish.y - start.y) / 2;
\r
10490 /* Don't use as many frames for very short moves */
\r
10491 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10492 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10494 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10496 animInfo.from.x = fromX;
\r
10497 animInfo.from.y = fromY;
\r
10498 animInfo.to.x = toX;
\r
10499 animInfo.to.y = toY;
\r
10500 animInfo.lastpos = start;
\r
10501 animInfo.piece = piece;
\r
10502 for (n = 0; n < nFrames; n++) {
\r
10503 animInfo.pos = frames[n];
\r
10504 DrawPosition(FALSE, NULL);
\r
10505 animInfo.lastpos = animInfo.pos;
\r
10506 Sleep(appData.animSpeed);
\r
10508 animInfo.pos = finish;
\r
10509 DrawPosition(FALSE, NULL);
\r
10510 animInfo.piece = EmptySquare;
\r
10513 /* Convert board position to corner of screen rect and color */
\r
10516 ScreenSquare(column, row, pt)
\r
10517 int column; int row; POINT * pt;
\r
10520 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10521 pt->y = lineGap + row * (squareSize + lineGap);
\r
10523 pt->x = lineGap + column * (squareSize + lineGap);
\r
10524 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10528 /* Generate a series of frame coords from start->mid->finish.
\r
10529 The movement rate doubles until the half way point is
\r
10530 reached, then halves back down to the final destination,
\r
10531 which gives a nice slow in/out effect. The algorithmn
\r
10532 may seem to generate too many intermediates for short
\r
10533 moves, but remember that the purpose is to attract the
\r
10534 viewers attention to the piece about to be moved and
\r
10535 then to where it ends up. Too few frames would be less
\r
10539 Tween(start, mid, finish, factor, frames, nFrames)
\r
10540 POINT * start; POINT * mid;
\r
10541 POINT * finish; int factor;
\r
10542 POINT frames[]; int * nFrames;
\r
10544 int n, fraction = 1, count = 0;
\r
10546 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10547 for (n = 0; n < factor; n++)
\r
10549 for (n = 0; n < factor; n++) {
\r
10550 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10551 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10553 fraction = fraction / 2;
\r
10557 frames[count] = *mid;
\r
10560 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10562 for (n = 0; n < factor; n++) {
\r
10563 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10564 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10566 fraction = fraction * 2;
\r
10568 *nFrames = count;
\r
10572 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10577 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10578 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10580 OutputDebugString( buf );
\r
10583 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10585 EvalGraphSet( first, last, current, pvInfoList );
\r
10588 void SetProgramStats( FrontEndProgramStats * stats )
\r
10593 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10594 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10596 OutputDebugString( buf );
\r
10599 EngineOutputUpdate( stats );
\r